我已经开始将各种常见的Image
移动到ResourceDictionary
中,并注意到我的WPF应用程序中存在一种奇怪的行为。如果Image
用于MenuItem
和ToolBar
上的Button
,当我打开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
中的资源警告,但我无法找到适当的解决方案。行为同时发生StaticResource
和DynamicResource
。它似乎也不会受到ResourceDictionary
是否独立存在或是否与其他合并的影响。也没有其他资源共享该密钥。
编辑:此外,向图像添加PresentationOptions:Freeze="True"
并没有改变情况。
Image 类是一个视觉对象,因此它只能出现在可视化树中的一个位置。因此,您不能在多个菜单项/按钮/等之间共享它。
但是,您可以共享 ImageSource(即 Image.Source(值。
在 WPF 中,我相信您可以使用 x:Shared="False" 来强制 WPF 为每个请求创建一个新实例。
不能在多个位置使用 Image 控件,它只能出现在可视化树中的一个位置,因此,如果调用资源,则会从以前的所有者那里抢夺图像。
编辑:x:Shared="False"
显然是比我下面的所有建议更好的解决方案,我想知道为什么如此重要的属性没有出现在智能感知中 -_-
这种行为有点痛苦,我通常用于预定义图像源的IconStyle
和BitmapImages
,但为可能需要的每个MenuItem
创建新图像。
您还可以为图标创建数据模板:
资源:
<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......
为了解决这个问题,你可以写一个标记扩展,这个非常简单,只复制Source
和Style
属性的值,你也可以使用反射或其他方式创建一个完整的副本:
[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>