【msdn wpf forum翻译】TextBlock等类型的默认样式(implicit style)为何有时不起作用?...
原文链接:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/148e95c6-6fb5-4399-8a56-41d0e0a72f1b
疑问:
以下代码定义了一个TextBlock的默认样式:
<Style.Triggers>
<Trigger Property="Text" Value="">
<Setter Property="Visibility" Value="Collapsed"/>
</Trigger>
</Style.Triggers>
</Style>
以下是TreeView的一个 HierarchicalDataTemplate 的定义:
<Grid x:Uid="Grid_7" Width="Auto" Height="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Image Grid.Column="0" Grid.Row="0" Margin="5,0,0,0"/>
<TextBlock Grid.Column="1" Grid.Row="0" Padding="5,0,0,0"/>
<TextBlock Grid.Column="2" Grid.Row="0" Foreground="Blue"Padding="5,0,0,0"/>
<TextBlock Grid.Column="3" Grid.Row="0" Foreground="Red"Padding="5,0,0,0"/>
</Grid>
</HierarchicalDataTemplate>
之后,就算我们把 TextBlock的默认样式加到<TreeView.Resources> 之中,TextBlock也不会像预期的那样(预期:如果为空串时 Visibility == Collapsed)。
Johnny Q. 回答:
这个行为“by design”,简而言之,当一个直接继承自 FrameworkElement 的对象在一个 FrameworkTemplate 之中时,默认样式不起作用(当该样式定义在 FrameworkTemplate 之外的逻辑树的祖先节点时)。
This is by design, as far as I know (if it's good or bad, that can be debatable; maybe things will change in future releases). For short, default styles do not work with objects directly derived from FrameworkElement, when placed inside FrameworkTemplate. See also http://shevaspace.blogspot.com/2007/03/wtf-of-wpf-part-one-templating-styling.html
注:
http://shevaspace.blogspot.com/2007/03/wtf-of-wpf-part-one-templating-styling.html (需FQ)中更为详细的描述了这个问题,给出了一个可以在 xamlpad 中演示的例子,并指出了这个行为是在 FrameworkElement.FindImplicitStyleResource() 函数中进行限制的。 以下先给出链接中的例子:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style TargetType="{x:Type TextBlock}" x:Key="textBlock">
<Setter Property="TextElement.Foreground" Value="Cyan"/>
</Style>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="TextElement.Foreground" Value="Cyan"/>
</Style>
<Style TargetType="{x:Type AccessText}">
<Setter Property="TextElement.Foreground" Value="Cyan"/>
</Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="Cyan"/>
</Style>
<Style TargetType="{x:Type InkCanvas}">
<Setter Property="Background" Value="Cyan"/>
</Style>
<Style TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="10"/>
<Setter Property="BorderBrush" Value="Cyan"/>
</Style>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Background" Value="Green"/>
</Style>
<Style TargetType="{x:Type Control}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Label>Inside Control</Label>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="template">
<!--WTF, StackPanel, TextBlock, AccessText, ContentPresenter, InkCanvas, Image, Rectangle,
MediaElement etc cannot pick up their respective implicit styles here,
one takeway from this empircal discovery is that Elements directly derived from FramworkElement cannot work in this scenario.-->
<StackPanel>
<TextBlock Name="tb">inside TextBlock</TextBlock>
<AccessText>inside AccessText</AccessText>
<ContentPresenter>
<ContentPresenter.Content>
inside ContentPresenter
</ContentPresenter.Content>
</ContentPresenter>
<InkCanvas/>
<Rectangle Width="40" Height="40"/>
<!--WTF, Border can pick up implicit style here.-->
<Border Width="200" Height="20"><TextBlock Name="tb2">bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb</TextBlock> </Border>
<!--WTF, Control can pick up implicit style here, since Border and Control can work here, our previous hypothesis breaks.-->
<Control/>
</StackPanel>
</ControlTemplate>
</Page.Resources>
<Control Template="{StaticResource template}"/>
</Page>
之后,我们打开 MS 发布的 wpf 的源代码(.net 3.0版)找到 FrameworkElement.FindImplicitStyleResource() 函数(注意参数重载,第一个参数为FrameworkElement的才是我们要找的):
1 // FindImplicitSytle(fe) : Default: unlinkedParent, deferReference
2 internal static object FindImplicitStyleResource(FrameworkElement fe, object resourceKey, out object source)
3 {
4 // Do a FindResource call only if someone in the ancestry has
5 // implicit styles. This is a performance optimization.
6
7 #if !DEBUG
8 if (fe.ShouldLookupImplicitStyles)
9 {
10 #endif
11 object unlinkedParent = null;
12 bool allowDeferredResourceReference = false;
13 bool mustReturnDeferredResourceReference = false;
14
15 // Implicit style lookup must stop at the app.
16 bool isImplicitStyleLookup = true;
17
18 // For non-controls the implicit StyleResource lookup must stop at
19 // the templated parent. Look at task 25606 for further details.
20 DependencyObject boundaryElement = null;
21 if (!(fe is Control))
22 {
23 boundaryElement = fe.TemplatedParent;
24 }
25
26 object implicitStyle = FindResourceInternal(fe, null, FrameworkElement.StyleProperty, resourceKey, unlinkedParent, allowDeferredResourceReference, mustReturnDeferredResourceReference, boundaryElement, isImplicitStyleLookup, out source);
27
28 // The reason this assert is commented is because there are specific scenarios when we can reach
29 // here even before the ShouldLookupImplicitStyles flag is updated. But this is still acceptable
30 // because the flag does get updated and the style property gets re-fetched soon after.
31
32 // Look at AccessText.GetVisualChild implementation for example and
33 // consider the following sequence of operations.
34
35 // 1. contentPresenter.AddVisualChild(accessText)
36 // 1.1. accessText._parent = contentPresenter
37 // 1.2. accessText.GetVisualChild()
38 // 1.2.1 accessText.AddVisualChild(textBlock)
39 // 1.2.1.1 textBlock.OnVisualParentChanged()
40 // 1.2.1.1.1 FindImplicitStyleResource(textBlock)
41 // .
42 // .
43 // .
44 // 1.3 accessText.OnVisualParentChanged
45 // 1.3.1 Set accessText.ShouldLookupImplicitStyle
46 // 1.3.2 FindImplicitStyleResource(accessText)
47 // 1.3.3 Set textBlock.ShouldLookupImplicitStyle
48 // 1.3.4 FindImplicitStyleResource(textBlock)
49
50 // Notice how we end up calling FindImplicitStyleResource on the textBlock before we have set the
51 // ShouldLookupImplicitStyle flag on either accessText or textBlock. However this is still acceptable
52 // because we eventually going to synchronize the flag and the style property value on both these objects.
53
54 // Debug.Assert(!(implicitStyle != DependencyProperty.UnsetValue && fe.ShouldLookupImplicitStyles == false),
55 // "ShouldLookupImplicitStyles is false even while there exists an implicit style in the lookup path. To be precise at source " + source);
56
57 return implicitStyle;
58 #if !DEBUG
59 }
60
61 source = null;
62 return DependencyProperty.UnsetValue;
63 #endif
64 }
65
在这里我们只需要关注两个地方:
1. 第4、5行的注释。
2. 第18-24行的注释及代码。
可知,如果FrameworkElement的 非Control子类 的对象,其默认样式的搜索边界是其TemplateParent,而MS是出于性能优化的角度,进行这样的设计的。
为什么值得这样设计呢?以下是我的分析、推测:
我们知道,Control 类有 Template 属性,依照上面的结论, ControlTemplate 中 FrameworkElement 的非Control子类 的对象,其默认样式的搜索边界就是 其 TemplateParent,这样设计之后,搜索默认样式的速度就会被加快(可通过使用Reflector+Reflector's baml viewer add-in 查看 PresentationFramework.Aero.dll 中的 themes/aero.normalcolor.baml 来查看 Aero 主题的控件的默认Template)。
回到篇首提到的那个问题,我们可知,可通过在HierarchicalDataTemplate 的 Grid.Resource 中定义 TextBlock 的默认样式来实现提问者想要的功能。
【msdn wpf forum翻译】TextBlock等类型的默认样式(implicit style)为何有时不起作用?...相关推荐
- 【msdn wpf forum翻译】获取当前窗口焦点所在的元素
原文:[msdn wpf forum翻译]获取当前窗口焦点所在的元素 原文地址: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6b ...
- 《Programming WPF》翻译 第3章 2.处理输入
原文:<Programming WPF>翻译 第3章 2.处理输入 在Windows应用程序中,又3种基本的用户输入形式:鼠标.键盘和手写板.同时,还有一种更高级输入方式,其可能来自快捷键 ...
- 《Programming WPF》翻译 第7章 4.转换
<Programming WPF>翻译 第7章 4.转换 原文:<Programming WPF>翻译 第7章 4.转换 支持高分辨率显示是WPF中的重要样式.这是被部分地支持 ...
- 《Programming WPF》翻译 第7章 3.笔刷和钢笔
原文:<Programming WPF>翻译 第7章 3.笔刷和钢笔 为了在屏幕上绘制一个图形,WPF需要知道你想要为图形填充什么颜色以及如何绘制它的边框.WPF提供了一些Brush类型支 ...
- 《Programming WPF》翻译 目录
原文:<Programming WPF>翻译 目录 注:第1.2章我只做了笔记,没有翻译,请大家阅读时注意. 还有就是,这本书的英文版本下载:[O'Reilly] Programming ...
- 《Programming WPF》翻译 第8章 2.Timeline
<Programming WPF>翻译 第8章 2.Timeline 原文:<Programming WPF>翻译 第8章 2.Timeline Timeline代表了时间的延 ...
- WPF编程,通过KeyFrame 类型制作控件线性动画的一种方法。
WPF编程,通过KeyFrame 类型制作控件线性动画的一种方法. 原文: WPF编程,通过KeyFrame 类型制作控件线性动画的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https ...
- 《Programming WPF》翻译 第8章 6.我们进行到哪里了?
<Programming WPF>翻译 第8章 6.我们进行到哪里了? 原文:<Programming WPF>翻译 第8章 6.我们进行到哪里了? 动画可以增强应用程序的交互 ...
- WPF编程,TextBlock中的文字修饰线(上划线,中划线,基线与下划线)的使用方法。...
WPF编程,TextBlock中的文字修饰线(上划线,中划线,基线与下划线)的使用方法. 原文:WPF编程,TextBlock中的文字修饰线(上划线,中划线,基线与下划线)的使用方法. 版权声明:我不 ...
最新文章
- C/C++版数据结构之链表三
- python3 出现错误:TypeError: must be str, not list
- 在Spring Boot中使用内存数据库
- 去掉WinLicense文件效验的方法
- SAP ERP里如何创建一个新的material类型
- Oracle数据库案例整理-Oracle系统执行时故障-Shared Pool内存不足导致数据库响应缓慢...
- Java方法中的参数太多,第1部分:自定义类型
- @清晰掉 C++ 中的 enum 结构在内存中是怎么存储的?
- git reflog
- oform java_客户端表单通用验证checkForm(oForm)(1)
- 推荐系统实践:基于数据集MovieLens构造简单推荐系统
- 怎么使用计算机英语段落,怎么在电脑word文档中添加英文朗读功能
- 视频编解码学习之四:视频处理及编码标准
- 荣耀MagicBook 2019 Intel版发布:性能新升级 续航长达15小时!
- 【unity】遇到Multiple precompiled assemblies with the same name的解决方案
- 给计算机主机吹灰,电脑主机多久清理一次灰合理一些?一点小建议给你
- pssh, pscp的用法
- Linux下访问处理器硬件信息原理:图形化工具RWLinux的诞生
- jdk版本8u201 8u202 区别
- 短信被微信困兽:运营商战或和