Images in XAML ResourceDictionary disappear on ToolBar when Menu opens

陌路散爱 提交于 2019-12-03 12:24:02

The Image class is a visual, so it can only appear in the visual tree in one location. Therefore, you cannot share it among multiple MenuItems/Buttons/etc.

You can however share the ImageSource (i.e. Image.Source) value.

In WPF, I believe you can use x:Shared="False" to force WPF to create a new instance for each request though.

You cannot use an Image control in multiple places, it can only be appear in the Visual Tree at one place, so if the call to the resource is made the image is being snatched from the previous owner.

Edit: x:Shared="False" Is obviously a better solution than all of my suggestions below, i wonder why such an important property does not show up in the Intellisense -_-


This behaviour is a bit of a pain, i normally use to predefine a IconStyle and the BitmapImages for the Source of the images but create new Images for every MenuItem where i might need it.

You can also create a DataTemplate for your Icon:

Resources:

    <Style x:Key="IconImageStyle" TargetType="{x:Type Image}">
        <Setter Property="MaxWidth" Value="16"/>
        <Setter Property="MaxHeight" Value="16"/>
    </Style>
    <DataTemplate x:Key="Icon_Close_Template">
        <Image Style="{StaticResource IconImageStyle}"
               Source="pack://application:,,,/Images/Close.ico"/>
    </DataTemplate>

Usage:

<Menu>
    <MenuItem Header="File">
        <MenuItem Header="Close">
            <MenuItem.Icon>
                <ContentPresenter ContentTemplate="{StaticResource Icon_Close_Template}"/>
            </MenuItem.Icon>
        </MenuItem>
        <MenuItem Header="Close">
            <MenuItem.Icon>
                <ContentPresenter ContentTemplate="{StaticResource Icon_Close_Template}"/>
            </MenuItem.Icon>
        </MenuItem>
    </MenuItem>
</Menu>

Since templates are created via factories this will work, still significantly inflates the XAML though...

To get around this you could for example write a markup extension, this one is very simple and only copies the values of the Source and Style properties, you could also use reflection or other means to create a complete copy:

[MarkupExtensionReturnType(typeof(object))]
public class IconExtension : MarkupExtension
{
    private Image icon;
    public Image Icon
    {
        get { return icon; }
        set { icon = value; }
    }

    public IconExtension() { }
    public IconExtension(Image icon)
    {
        Icon = icon;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (Icon == null) throw new ArgumentNullException("Icon");
        return new Image() { Source = Icon.Source, Style = Icon.Style };
    }
}

Can be used like this:

<Style x:Key="IconImageStyle" TargetType="{x:Type Image}">
    <Setter Property="MaxWidth" Value="16"/>
    <Setter Property="MaxHeight" Value="16"/>
</Style>
<Image x:Key="Icon_Close"  Style="{StaticResource IconImageStyle}" Source="pack://application:,,,/Images/Close.ico"/>
<!-- ... -->
<MenuItem Header="File">
    <MenuItem Header="Close" Icon="{m:Icon {StaticResource Icon_Close}}"/>
    <MenuItem Header="Close" Icon="{m:Icon {StaticResource Icon_Close}}"/>
</MenuItem>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!