我有兩種基本相同的數據模板在解決隱式樣式資源方式方面表現完全不同的情況。這種不一致使得我正在處理的大型應用程序難以處理應用程序範圍的資源。通過數據模板解決WPF合併資源不一致
情景。
我在名爲AppStyles.xaml的獨立xaml文件中有一個ResourceDictionary。它爲Button和TextBlock類定義了一個隱式樣式。
<!-- AppStyles.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="Padding" Value="10"/>
<Setter Property="Background" Value="Red"/>
</Style>
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Width" Value="300"/>
</Style>
</ResourceDictionary>
我的MainWindow.xaml文件將AppStyles.xaml合併到它自己的資源中。 MainWindow.xaml包含兩個ContentPresenter,每個ContentPresenter都綁定到一個簡單的viewmodel類。第一個ContentPresenter使用的數據模板是在MainWindow.xaml中內聯聲明的UserControl,第二個ContentPresenter使用的數據模板也是內聯聲明的,但引用在單獨文件中定義的UserControl。兩個數據模板使用的UserControl的實際聲明在其他方面是相同的。
<!-- MainWindow.xaml -->
<Window x:Class="Demo2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Demo2"
Title="MainWindow" Height="350" Width="525"
x:Name="_this">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/AppStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<DataTemplate DataType="{x:Type local:TemplateVm1}">
<UserControl>
<StackPanel>
<TextBlock Text="{Binding TextBlockValue}"/>
<Button Content="{Binding ButtonValue}"/>
</StackPanel>
</UserControl>
</DataTemplate>
<DataTemplate DataType="{x:Type local:TemplateVm2}">
<local:UserControl1/>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<ContentPresenter Content="{Binding ElementName=_this, Path=TemplateVm1}"/>
<ContentPresenter Content="{Binding ElementName=_this, Path=TemplateVm2}"/>
</StackPanel>
</Window>
問題。
問題是兩個ContentPresenter呈現完全不同! ContentPresenters都使用AppStyles.xaml中的樣式呈現Button,但第一個ContentPresenter不應用隱式TextBlock樣式,而第二個則會應用。
我的期望是TextBlock樣式不會應用於由ContentPresenter顯示的模板,這是由於WPF行爲,只有從Control派生的組件纔會在當前模板之外查看資源,並且TextBlock不會從控制)。
那麼這裏發生了什麼,我該如何讓它表現得一貫?
爲了完整的例子,這裏是viewmodels和MainWindow代碼的實現,以及第二個模板中使用的UserControl。
// TemplateVm.cs
namespace Demo2
{
public class TemplateVm1
{
public TemplateVm1()
{
TextBlockValue = "TextBlock in ContentPresenter1.";
ButtonValue = "Button in ContentPresenter1";
}
public string TextBlockValue { get; private set; }
public string ButtonValue { get; private set; }
}
public class TemplateVm2
{
public TemplateVm2()
{
TextBlockValue = "TextBlock in ContentPresenter2.";
ButtonValue = "Button in ContentPresenter2";
}
public string TextBlockValue { get; private set; }
public string ButtonValue { get; private set; }
}
}
// MainWindow.xaml.cs
namespace Demo2
{
using System.Windows;
public partial class MainWindow : Window
{
public MainWindow()
{
TemplateVm1 = new TemplateVm1();
TemplateVm2 = new TemplateVm2();
InitializeComponent();
}
public TemplateVm1 TemplateVm1 { get; private set; }
public TemplateVm2 TemplateVm2 { get; private set; }
}
}
<!-- UserControl1.xaml -->
<UserControl x:Class="Demo2.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<TextBlock Text="{Binding TextBlockValue}"/>
<Button Content="{Binding ButtonValue}"/>
</StackPanel>
</UserControl>
嗯,我也有點困惑,爲什麼這種情況正在發生,但是當你合併您AppStyles進入App.xaml中你應該得到一個一致的行爲。如果這不起作用,一種方法是在UserControl中合併xaml,但我強烈建議不要這種解決方案。你真的確定使用了一種風格,而另一種風格是不是可以通過設置背景色等更多有意義的屬性來確認? – dowhilefor
合併到App.xaml中的資源適用於其他地方合併的資源,因爲合併到App.xaml中的任何資源都適用於絕對一切。所以是的,我可以將AppStyles.xaml放入App.xaml,然後將TextBlock樣式應用於兩個模板。但由於應用App.xaml資源的方式不同,因此TextBlock樣式也將應用於Button中(因爲它們在默認ControlTemplates中具有TextBlocks),這是最不可取的,因爲我只希望應用樣式應用應用程序聲明的控件。 – Neutrino
我非常確定,在第一個模板的情況下,應用了Button的樣式,而TextBlock的樣式未應用。我已經用寬度和背景屬性對它進行了測試。在第二個模板的情況下,Button和TextBlock都被應用。 – Neutrino