开发者

WPF - MenuItem missing Icon/Image

开发者 https://www.devze.com 2023-01-29 10:54 出处:网络
Im getting menuItem icon appearing only on last menuItem. If i snoop the app only last menuItem has image in icon, while if i debug all MenuItems appear to have image in icon. Also if i add submenuIte

Im getting menuItem icon appearing only on last menuItem. If i snoop the app only last menuItem has image in icon, while if i debug all MenuItems appear to have image in icon. Also if i add submenuItem the icon on menuItem dissapears once i open submenus and the last submenu gets the icon... Any idea? PS: also tooltips on menu item dont work. Im using caliburn micro and fluent ribbon controls.

        <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="Header" 
                            Value="{Binding DisplayName}"/>
                    <Setter Property="Icon">
                        <Setter.Value>
                            <Image Source="{Binding Path=IconPath}"/>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="ItemsSource" 
                            Value="{Binding Items}"/>
                    <Setter Property="cm:Message.Attach" 
                            Value="ClickAction()"/>
                    <Setter Propert开发者_JAVA技巧y="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>


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.


1. Add Existing File... image file to resources (if you already have one, skip it).

WPF - MenuItem missing Icon/Image

2. In Solution Explorer select this image file.

3. Change Build Action to Resource.

WPF - MenuItem missing Icon/Image

And finally, you can add this image to XAML with simple call:

<Window.Resources>
    <ContextMenu x:Key="contextMenu" >
        <MenuItem Header="Restart" Name="menuItemRestart" Click="MenuItem_Click">
            <MenuItem.Icon>
                <Image Source="/Resources/restart.png"/>
            </MenuItem.Icon>
        </MenuItem>
        <Separator/>
        <MenuItem Header="Exit" Name="menuItemExit" Click="MenuItem_Click">
            <MenuItem.Icon>
                <Image Source="/Resources/window_close.png"/>
            </MenuItem.Icon>
        </MenuItem>
    </ContextMenu>
</Window.Resources>

The Result:

WPF - MenuItem missing Icon/Image

0

精彩评论

暂无评论...
验证码 换一张
取 消