![](/img/trans.png)
[英]Is there any way to ignore application resources in contentpresenter
[英]ContentPresenter steals resources?
在一個簡單的視圖中,我想顯示兩個按鈕,它們具有內容圖像,這些圖像是通過資源以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是否會以某種方式阻止共享資源?
如另一個答案中所述,您應該在Button的ContentTemplate中具有Image控件。
用其Source屬性綁定到實際Content的Image聲明一個簡單的Image Button樣式:
<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>
此行為的核心原因是一個元素只能在視覺樹中出現一次。
首先,默認情況下, ResourceDictionary
中的ResourceDictionary
是共享的,即,每次使用特定鍵獲取資源時,您總是會得到相同的實例。 在您的情況下,您總是會得到相同的Style
實例,這也意味着(每個樣式)總是只有一個Image
實例。
因此,如果將相同的樣式應用於兩個按鈕,則框架會嘗試將相同的Image
實例放置在兩個不同的位置,這是不允許的。 為避免這種情況,在嘗試將圖像加載到視覺樹中時,如果圖像已經在視覺樹中,則首先從先前的位置將其卸載。
這就是為什么僅在最后一個按鈕(按加載順序)中可見圖像的原因。
對於這個問題,基本上有兩種解決方案。
1.禁用資源共享
您可以禁用資源共享,以便每次從ResourceDictionary
獲取ResourceDictionary
都會獲得該資源的新實例。 為此,請在資源上設置x:Shared="False"
:
<Style x:Key="AddButtonWithIconStyle" x:Shared="False" TargetType="{x:Type Button}">
(...)
</Style>
2.以您的樣式使用ContentTemplate
可以將ContentTemplate
定義為ContentTemplate
,而不是將圖像作為按鈕的內容,而是將其分別應用於每個按鈕(因此每個按鈕都有自己的圖像實例):
<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中模板的目的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.