在一个简单的视图中,我想显示两个按钮,这些按钮具有内容图像,这些按钮是通过App.xaml中加载的额外style.xaml中的资源提供的。
<BitmapImage x:Key="AddIcon" UriSource="pack://application:,,,/WpfTestBench;component/Images/plus.png"></BitmapImage>
<BitmapImage x:Key="RemoveIcon" UriSource="pack://application:,,,/WpfTestBench;component/Images/minus.png"></BitmapImage>
<Style x:Key="AddButtonWithIconStyle" TargetType="{x:Type Button}">
<Setter Property="Content">
<Setter.Value>
<Image Source="{DynamicResource AddIcon}" Stretch="None"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="RemoveButtonWithIconStyle" TargetType="{x:Type Button}">
<Setter Property="Content">
<Setter.Value>
<Image Source="{DynamicResource RemoveIcon}" Stretch="None"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Setter.Value>
</Setter>
</Style>
在我看来,我使用这样的样式:
<DockPanel Margin="0,0,5,0" DockPanel.Dock="Bottom" LastChildFill="False" >
<Button Command="{Binding DeleteCommand}" DockPanel.Dock="Right"
Style="{StaticResource RemoveButtonWithIconStyle}"/>
<Button Command="{Binding AddCommand}" DockPanel.Dock="Right" Margin="5,0"
Style="{StaticResource AddButtonWithIconStyle}"/>
</DockPanel>
到目前为止这看起来不错。 但是当我通过ContentPresenter将另一个视图添加到此视图中时,它具有基本相同的内容(再次使用上述按钮样式),前两个按钮(父视图)的显示不再起作用。我得到的只有两个带有按钮功能的小圆圈。
<ContentPresenter Content="{Binding SomeEmbeddedViewModel, UpdateSourceTrigger=PropertyChanged}"/>
为什么会这样? ContentPresenter是否会以某种方式阻止共享资源?
答案 0 :(得分:2)
正如在另一个答案中所解释的那样,你应该在Button的ContentTemplate中拥有Image控件。
声明一个简单的图像按钮样式,其图像的Source属性绑定到实际内容:
<Style x:Key="ImageButtonStyle" TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
...
<Button Style="{StaticResource ImageButtonStyle}"
Content="{DynamicResource RemoveIcon}" .../>
您也可以将样式声明为默认按钮样式,可能在DockPanel中:
<DockPanel>
<DockPanel.Resources>
<Style TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding}" Stretch="None"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DockPanel.Resources>
<Button Command="{Binding DeleteCommand}" DockPanel.Dock="Right"
Content="{DynamicResource RemoveIcon}"/>
<Button Command="{Binding AddCommand}" DockPanel.Dock="Right" Margin="5,0"
Content="{DynamicResource AddIcon}"/>
</DockPanel>
答案 1 :(得分:1)
此行为的核心原因是元素只能在可视树中出现一次。
首先,ResourceDictionary
中的资源默认是共享的,即每次获取具有特定键的资源时,您总是获得相同的实例。在您的情况下,您始终获得Style
的相同实例,这也意味着始终只有Image
的一个实例(针对每种风格)。
因此,如果将相同的样式应用于两个按钮,框架会尝试将相同的Image
实例放在两个不同的位置,这是不允许的。为了避免这种情况,在尝试将图像加载到可视树中时,如果它已经在可视化树中,则首先从先前位置卸载它。
这就是为什么图像只能在最后一个按钮中显示(按照加载顺序)。
这个问题基本上有两种解决方案。
<强> 1。禁用资源共享
您可以禁用资源共享,这样每次从ResourceDictionary
获取资源时,您都会获得资源的新实例。为此,您需要在资源上设置x:Shared="False"
:
<Style x:Key="AddButtonWithIconStyle" x:Shared="False" TargetType="{x:Type Button}">
(...)
</Style>
<强> 2。在您的风格中使用ContentTemplate
不是将图像作为按钮的内容放置,而是可以定义ContentTemplate
,它是针对应用的每个按钮单独实现的(因此每个按钮都有自己的图像实例): / p>
<Style x:Key="RemoveButtonWithIconStyle" TargetType="{x:Type Button}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{DynamicResource RemoveIcon}" Stretch="None"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
就我个人而言,我建议您使用第二种解决方案,因为这正是 WPF 中模板的用途。