菜单打开时,XAML ResourceDictionary中的图像在ToolBar上消失

时间:2011-04-08 15:46:02

标签: wpf resourcedictionary

我已经开始将各种常见的Image移动到ResourceDictionary,并注意到我的WPF应用程序中存在奇怪的行为。如果在ImageMenuItem Button中使用了ToolBar,当我打开Menu时,Button上的图片就消失了}。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Image x:Key="NewImage"
           Source="/SomeApplication;component/Resources/NewDocumentHS.png"
           Stretch="None"/>
    <!-- ... -->

来自Window的相关XAML:

<Menu>
    <MenuItem Header="_File">
        <MenuItem Header="_New"
                  Command="{Binding NewCommand}"
                  Icon="{DynamicResource NewImage}" />
<!-- ... -->
<ToolBarTray>
    <ToolBar>
        <Button Command="{Binding NewCommand}"
                Content="{DynamicResource NewImage}" />

我认为这是ResourceDictionary中的资源警告,但我无法找到适当的解决方法。 StaticResourceDynamicResource都会出现行为。如果ResourceDictionary独立或者与其他人合并,它似乎也不会受到影响。没有其他资源可以共享密钥。

修改:此外,向图片添加PresentationOptions:Freeze="True"并未改变这种情况。

2 个答案:

答案 0 :(得分:8)

Image类是可视化的,因此它只能在一个位置的可视树中出现。因此,您无法在多个MenuItems / Buttons / etc.之间共享它。

但是,您可以共享ImageSource(即Image.Source)值。

在WPF中,我相信您可以使用x:Shared =“False”来强制WPF为每个请求创建一个新实例。

答案 1 :(得分:2)

您不能在多个地方使用Image控件,它只能在一个地方出现在Visual Tree中,因此如果调用该资源,则会从前一个所有者中抢夺该图像。

编辑: x:Shared="False"显然比下面的所有建议更好的解决方案,我想知道为什么这样一个重要的属性不会出现在Intellisense -_-


这种行为有点痛苦,我通常用来为图像的来源预定义IconStyleBitmapImages,但为每个MenuItem创建新图像需要它。

您还可以为Icon创建一个DataTemplate:

资源:

    <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>

用法:

<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>

由于模板是通过工厂创建的,这将起作用,但仍然会显着膨胀XAML ......

为了解决这个问题,您可以编写一个标记扩展,这个非常简单,只复制SourceStyle属性的值,您也可以使用反射或其他方法来创建一个完整的副本:

[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 };
    }
}

可以像这样使用:

<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>