我正在查看this question,并注意到在TextBlock
中放置一个隐式Application.Resources
样式会将该样式应用于所有TextBlock,即使是Buttons
等其他控件内的那些样式, ComboBoxes
等等
<Application.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Blue" />
</Style>
</Application.Resources>
将隐式样式放在Window.Resources
does not cross control template boundaries中,因此Buttons
和ComboBoxes
之类的内容会保留默认的黑色文字。
<Window.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Blue" />
</Style>
</Window.Resources>
此外,在Application.Resources
中添加默认样式会使您无法使用其他隐式样式覆盖该样式。
<!-- Doesn't work if implicit style with same property is in Application.Resources -->
<ComboBox.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Red" />
</Style>
</ComboBox.Resources>
我的问题是:
Application.Resources
和Windows.Resources
之间是否存在其他差异? 何时应该使用一个而不是另一个?
我了解Application.Resources
适用于整个应用,而Window.Resources
仅适用于该窗口,但我想知道为什么Application
中的样式与{中的样式的处理方式不同{1}}
答案 0 :(得分:23)
这实际上是WPF中唯一的特殊处理,它是由设计完成的。实现它的代码可以在方法FrameworkElement
的{{1}}中找到,它实际上有效:
FindImplicitStyleResource
因此,经验法则是隐式样式总是应用于控件(即从internal static object FindImplicitStyleResource(FrameworkElement fe, object resourceKey, out object source)
{
// ...
DependencyObject boundaryElement = null;
if (!(fe is Control))
boundaryElement = fe.TemplatedParent;
// ...
}
派生)。假设可以找到隐式Style。
对于Control
中未使用ControlTemplate
派生的元素,例如Control
,隐式样式查找不会跨越它的模板化父级。在您的情况下,这将是TextBlock
。
我相信这样做是为了使非应用程序隐式的TextBlock样式不会无意中应用于控件模板中使用的ComboBox
元素,开发人员可能会或可能不知道这些元素。隐式样式只会应用于开发人员在他们自己的XAML中实际创建的TextBlock。
应用程序隐式样式仍然允许全局样式,例如增加字体大小。但可能造成了更多的混乱而不是它的价值。
没有什么好的答案可以说明何时使用它们,因为它们各自都有它们的功能。显然,如果您不想影响应用程序中的每个TextBlock
,则不应将样式放在应用程序资源中。
但请注意,这会影响任何非TextBlock
元素,例如Control
元素。
答案 1 :(得分:2)
非常简单明了
如果您希望在ENTIRE应用程序之间共享资源,您可以使用Application.Resources
如果您希望在整个窗口之间共享资源,您可以使用Window.Resources
如果您希望在您使用的单个控件之间共享资源(Whatever Control).Resources
假设您有多个窗口,但您只想在一个窗口中使用默认样式而不是另一个窗口,那么您将使用Windoe.Resources
答案 2 :(得分:0)
不同之处在于风格的范围:
差异在那里非常微妙,但它意味着无论我们谈论什么控件(包括在另一个控件模板中的控件)都将从application.Resources获得样式。但只有控件直接窗口的子窗口才会从window.Resources获取样式。 antoher控件模板中的控件将不具有Window.Resources中定义的样式,因为它不直接在窗口中,而它将具有Application.Resources中定义的样式,因为它在应用程序中。
关于你的第二点,它与我认为的依赖属性优先级有关:
答案 3 :(得分:0)
没有这样的等级。 WPF应用程序中有不同的树,最着名的是逻辑树和可视树,但还有更多(路由事件树和资源查找树,语义略有不同)。
假设以下XAML:
<Window x:Class="SO.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="btn" Click="click">Click Me</Button>
</Grid>
</Window>
对于此XAML,逻辑树将如下所示:
- Window =&gt;网格=&gt;按钮=&gt;串
按钮内的文本块不是逻辑树的一部分(虽然它是VisualTree的一部分)。
通过LogicalTree查找资源,但有一点不同。到达顶层对象后,查找资源算法将查看 Application 资源字典,然后查看 Theme 资源字典,然后查看 System < / em>此顺序的资源字典。
参见以下文章:
Finnaly,为了证明我的观点,将以下资源添加到应用程序XAML中:
<Application x:Class="SO.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:clr="clr-namespace:System;assembly=mscorlib"
StartupUri="MainWindow.xaml">
<Application.Resources>
<clr:String x:Key="MyResource">Hello Application Resource</clr:String>
</Application.Resources>
</Application>
以及后面的代码:
private void click(object sender, RoutedEventArgs e)
{
// Logical Children of btn
Debug.WriteLine("Children of btn:");
foreach( var x in LogicalTreeHelper.GetChildren(btn) ) {
Debug.WriteLine("{0} : {1}", x, x.GetType());
}
// Walk the visual tree
Debug.WriteLine("The Visual Tree:");
WalkVisual(0, this);
// Find the textblock within the button
DependencyObject p = btn;
while (p.GetType() != typeof(TextBlock))
p = VisualTreeHelper.GetChild(p, 0);
TextBlock tb = p as TextBlock;
// Now climp the textblock through the logical tree
while (p != null)
{
Debug.WriteLine("{0}", p.GetType());
p = LogicalTreeHelper.GetParent(p);
}
// Find a resource for the textbox
string s = tb.FindResource("MyResource") as string;
Debug.WriteLine("MyResource Content: {0}", s);
}
private void WalkVisual(int indent, DependencyObject p)
{
string fmt = string.Format("{{0,{0}}}{{1}}", indent * 4);
Debug.WriteLine(fmt, "", p.GetType());
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(p); ++i)
{
WalkVisual(indent+1,VisualTreeHelper.GetChild(p, i));
}
}
所以......一旦你理解了第一个问题(“为什么会这样”),其他问题就会崩溃。应用程序资源和窗口资源之间的不同之处在于,应用程序资源可以由应用程序中的任何DependencyObject(包括在其他程序集中定义的那些)来配置。当你想要实现这个目标时,你会使用它: - )
Ú