WPF - MenuItem missing Icon/Image

不想你离开。 提交于 2019-11-30 20:32:39
decyclone

You are setting Icon property to an Image control in Style. Now, only one copy of Style is created and thus, only one copy of Image is created. Now, any control can have only one parent at a time. So, when it is assigned to last MenuItem, it is removed from previous MenuItem controls. To fix this, use Templates.

Instead of setting Header property, set HeaderTemplate:

            <Setter Property="HeaderTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Image Grid.Column="0"
                                   Source="{Binding Path=IconPath}" />
                            <TextBlock Grid.Column="1"
                                       Text="{Binding DisplayName}" />
                        </Grid>
                    </DataTemplate>
                </Setter.Value>
            </Setter>

I'm not sure of what properties are exposed by the control toolkit you are using. But, I'm sure they must have a template property.

After doing this, you don't need to set Icon property in style.

I successfully use the following entries in a ResourceDictionary:

<!-- Define non-shared image to avoid loss of menu icons -->
<Image x:Key="MenuIconImage" Height="16" Width="16" x:Shared="false">
    <Image.Source>
        <DrawingImage Drawing="{Binding Icon}" />
    </Image.Source>
</Image>

<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}">
    <Setter Property="Header" Value="{Binding DisplayName />
    <Setter Property="Icon" Value="{StaticResource MenuIconImage}" />
</Style>

Works like this:

       <DataTemplate x:Key="MenuItemHeaderTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Image Grid.Column="0" Source="{Binding Path=IconPath}" />
            <Label Grid.Column="1" Content="{Binding DisplayName}" />               
        </Grid>
    </DataTemplate>


    <ControlTemplate x:Key="dropDownButton">
        <ef:DropDownButton Header="{Binding DisplayName}" 
                           ItemsSource="{Binding Items}" 
                           LargeIcon="{Binding LargeIconPath}" 
                           cm:Message.Attach="ClickAction()" 
                           ef:KeyTip.Keys="{Binding KeyTip}">
            <ef:DropDownButton.ItemContainerStyle>
                <Style TargetType="MenuItem">
                    <Setter Property="HeaderTemplate" Value="{StaticResource MenuItemHeaderTemplate}" />                                 
                    <Setter Property="ItemsSource" 
                            Value="{Binding Items}"/>
                    <Setter Property="cm:Message.Attach" 
                            Value="ClickAction()"/>
                    <Setter Property="ef:KeyTip.Keys" 
                            Value="{Binding KeyTip}"/>
                    <Setter Property="ToolTip">
                        <Setter.Value>
                            <ef:ScreenTip Title="{Binding DisplayName}"
                                          HelpTopic="ScreenTip help ..."
                                          Image="{Binding LargeIconPath}"
                                          Text="Text for ScreenTip"/>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ef:DropDownButton.ItemContainerStyle>
            <ef:DropDownButton.ToolTip>
                <ef:ScreenTip Title="{Binding DisplayName}"
                              HelpTopic="ScreenTip help ..."
                              Image="{Binding LargeIconPath}"
                              Text="Text for ScreenTip"/>
            </ef:DropDownButton.ToolTip>
        </ef:DropDownButton>

For some reason approach when Image is static resource with x:Shared = false doesn't work for me. Only last menu item shows icon. I've tried both StaticResource and DynamicResource. Here is my solution:

public class MenuItemIconHelper
{
    #region ImageSource Icon

    public static readonly DependencyProperty IconProperty = DependencyProperty.RegisterAttached("Icon", typeof(ImageSource), typeof(MenuItemIconHelper), new PropertyMetadata(default(ImageSource), IconPropertyChangedCallback));

    private static void IconPropertyChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var i = (MenuItem)obj;

        if (e.NewValue != null)
            i.Icon = new Image() {Source = (ImageSource)e.NewValue};
        else
            i.Icon = null;
    }

    public static void SetIcon(DependencyObject element, ImageSource value)
    {
        element.SetValue(IconProperty, value);
    }

    public static ImageSource GetIcon(DependencyObject element)
    {
        return (ImageSource)element.GetValue(IconProperty);
    }

    #endregion
}

Sample:

<Style x:Key="CommandMenuItemStyle" TargetType="MenuItem">
<Setter Property="cb:MenuItemIconHelper.Icon" Value="car1.png" />
<Setter Property="Header" Value="{Binding Name}" />

I consider it to be more readable than using resource and you don't need to change MenuItem's HeaderTemplate. You can also implement some caching mechanism for ImageSource or Image.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!