【msdn wpf forum翻译】TextBlock等类型的默认样式(implicit style)为何有时不起作用?
原文:【msdn wpf forum翻译】TextBlock等类型的默认样式(implicit style)为何有时不起作用?
原文链接:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/148e95c6-6fb5-4399-8a56-41d0e0a72f1b
疑问:
以下代码定义了一个TextBlock的默认样式:
<Style TargetType="{x:Type TextBlock}"> <Style.Triggers> <Trigger Property="Text" Value=""> <Setter Property="Visibility" Value="Collapsed"/> </Trigger> </Style.Triggers> </Style>
以下是TreeView的一个 HierarchicalDataTemplate 的定义:
<HierarchicalDataTemplate DataType="XYZ" ItemsSource ="{Binding}"> <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() 函数中进行限制的。 以下先给出链接中的例子:
Code<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的才是我们要找的):
Code 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 #endif11 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 at19 // 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 reach29 // 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 = contentPresenter37 // 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.OnVisualParentChanged45 // 1.3.1 Set accessText.ShouldLookupImplicitStyle46 // 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 acceptable52 // 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 #endif64 }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翻译】TextBox中文本 中对齐 的方法
原文:[msdn wpf forum翻译]TextBox中文本 中对齐 的方法 原文链接:http://social.msdn.microsoft.com/Forums/en-US/wpf/threa ...
- 【msdn wpf forum翻译】获取当前窗口焦点所在的元素
原文:[msdn wpf forum翻译]获取当前窗口焦点所在的元素 原文地址: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6b ...
- 【msdn wpf forum翻译】如何在wpf程序(程序激活时)中捕获所有的键盘输入,而不管哪个元素获得焦点?
原文:[msdn wpf forum翻译]如何在wpf程序(程序激活时)中捕获所有的键盘输入,而不管哪个元素获得焦点? 原文链接:http://social.msdn.microsoft.com/Fo ...
- 《Programming WPF》翻译 第9章 5.默认可视化
原文:<Programming WPF>翻译 第9章 5.默认可视化 虽然为控件提供一个自定义外观的能力是有用的,开发者应该能够使用一个控件而不用必须提供自定义可视化.这个控件应该正好工作 ...
- 《Programming WPF》翻译 第5章 4.元素类型样式
原文:<Programming WPF>翻译 第5章 4.元素类型样式 命名样式非常有用,当你得到一组属性并应用到特点的元素上.然而,如果你想要应用一个统一的样式到所有确定元素类型的实例, ...
- 《Programming WPF》翻译 第9章 2.选择一个基类
原文:<Programming WPF>翻译 第9章 2.选择一个基类 WPF提供了很多类,当创建一个自定义元素时,你可以从这些类中派生.图9-1显示了一组可能作为类--可能是合适的基类, ...
- 《Programming WPF》翻译 第8章 3.Storyboard
原文:<Programming WPF>翻译 第8章 3.Storyboard Storyboard是动画的集合.如果你使用了标记,所有的动画必须要被定义在一个Storyboard中.(在 ...
- 《Programming WPF》翻译 第7章 4.转换
原文:<Programming WPF>翻译 第7章 4.转换 支持高分辨率显示是WPF中的重要样式.这是被部分地支持--强调了可伸缩的向量图,而不是图像.但是,正如使用GDI+和GDI3 ...
- 《Programming WPF》翻译 第7章 1.图形基础
原文:<Programming WPF>翻译 第7章 1.图形基础 WPF使得在你的应用程序中使用图形很容易,以及更容易开发你的显卡的能力.这有很多图形构架的方面来达到这个目标.其中最重要 ...
随机推荐
- 阿里云centos 6.5 32位安装可视化界面的方法
http://www.dzbfsj.com/forum.php?mod=viewthread&tid=2702 http://www.mayanpeng.cn/?p=507 http://bl ...
- Qt 子窗口内嵌到父窗口中
有时需要把一个子窗口内嵌进入父窗口当中. 我们可以这样做 1.新建一个QWidget 或者QDialog的子类 ClassA(父类为ClassB) 2.在新建类的构造函数中添加设置窗口属性 setWi ...
- HDU2473 Junk-Mail Filter - 并查集删除操作(虚父节点)
传送门 题意: 每次合并两份邮件,或者将某一份邮件独立出来,问最后有多少个邮件集合. 分析: 考虑初始化每个节点的祖先为一个虚父节点(i + n),虚父节点指向它自己.这样可以进行正常的合并操作. 而 ...
- asp.net core2.1 部署centos7/linux系统 -- 安装部署(一)
原文:asp.net core2.1 部署centos7/linux系统 -- 安装部署(一) 1.安装dotnet sdk(添加产品秘钥与yum源) 添加yum源:sudo rpm -Uvh htt ...
- [SVG] Add an SVG as a Background Image
Learn how to set an SVG as the background image of an element. Background images can be resized by c ...
- js进阶 9-7 自动计算商品价值
js进阶 9-7 自动计算商品价值 一.总结 一句话总结: 1.form表单控件value属性:属性可取值可赋值 2.文本onchange事件 3.form及form中控件通过name访问元素 二. ...
- 理解Erlang/OTP - Application
http://www.cnblogs.com/me-sa/archive/2011/12/27/erlang0025.html 1>application:start(log4erl). 我们就 ...
- 【BZOJ 1007】 [HNOI2008]水平可见直线
[题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1007 [题意] [题解] 这个人讲得很好 http://blog.csdn.net/o ...
- ASCII码(转)
ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧 ...
- CreateFileMapping和MapViewOfFile函数
大家都是到PG是分布式网络事务处理数据库,与其他数据库优点之一就在于服务器与客户的交流是一对一的,所谓一对一是指,针对客户的每一连接服务器都会产生一个进程为其服务,那么问题就来了,这些进程间是如何交互 ...