原文:【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)为何有时不起作用?的更多相关文章

  1. 【msdn wpf forum翻译】TextBox中文本 中对齐 的方法

    原文:[msdn wpf forum翻译]TextBox中文本 中对齐 的方法 原文链接:http://social.msdn.microsoft.com/Forums/en-US/wpf/threa ...

  2. 【msdn wpf forum翻译】获取当前窗口焦点所在的元素

    原文:[msdn wpf forum翻译]获取当前窗口焦点所在的元素 原文地址: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6b ...

  3. 【msdn wpf forum翻译】如何在wpf程序(程序激活时)中捕获所有的键盘输入,而不管哪个元素获得焦点?

    原文:[msdn wpf forum翻译]如何在wpf程序(程序激活时)中捕获所有的键盘输入,而不管哪个元素获得焦点? 原文链接:http://social.msdn.microsoft.com/Fo ...

  4. 《Programming WPF》翻译 第9章 5.默认可视化

    原文:<Programming WPF>翻译 第9章 5.默认可视化 虽然为控件提供一个自定义外观的能力是有用的,开发者应该能够使用一个控件而不用必须提供自定义可视化.这个控件应该正好工作 ...

  5. 《Programming WPF》翻译 第5章 4.元素类型样式

    原文:<Programming WPF>翻译 第5章 4.元素类型样式 命名样式非常有用,当你得到一组属性并应用到特点的元素上.然而,如果你想要应用一个统一的样式到所有确定元素类型的实例, ...

  6. 《Programming WPF》翻译 第9章 2.选择一个基类

    原文:<Programming WPF>翻译 第9章 2.选择一个基类 WPF提供了很多类,当创建一个自定义元素时,你可以从这些类中派生.图9-1显示了一组可能作为类--可能是合适的基类, ...

  7. 《Programming WPF》翻译 第8章 3.Storyboard

    原文:<Programming WPF>翻译 第8章 3.Storyboard Storyboard是动画的集合.如果你使用了标记,所有的动画必须要被定义在一个Storyboard中.(在 ...

  8. 《Programming WPF》翻译 第7章 4.转换

    原文:<Programming WPF>翻译 第7章 4.转换 支持高分辨率显示是WPF中的重要样式.这是被部分地支持--强调了可伸缩的向量图,而不是图像.但是,正如使用GDI+和GDI3 ...

  9. 《Programming WPF》翻译 第7章 1.图形基础

    原文:<Programming WPF>翻译 第7章 1.图形基础 WPF使得在你的应用程序中使用图形很容易,以及更容易开发你的显卡的能力.这有很多图形构架的方面来达到这个目标.其中最重要 ...

随机推荐

  1. jQuery 淡入淡出

    演示 jQuery fadeIn() 方法: <!DOCTYPE html> <html> <head> <meta charset="utf-8& ...

  2. 在线生成 QR Code

    http://tool.oschina.net/qr 在线生成二维码(QR码)-采用ZXing与d-project

  3. poj 2689 Prime Distance(大区间筛素数)

    http://poj.org/problem?id=2689 题意:给出一个大区间[L,U],分别求出该区间内连续的相差最小和相差最大的素数对. 由于L<U<=2147483647,直接筛 ...

  4. QQ欢乐斗地主心得体会 (三):高倍场攻略

    上个月,也可能是上个月的上个月,我的欢乐豆兵积攒到了百万之众,突破了历史记录.最近2个月一直在高倍场混,想写点高倍场的心得体会.本篇的体会,与以前写的2篇斗地主心得体会,有点不同. 特别说明:我主要玩 ...

  5. Java多线程编程— 概念以及经常使用控制

    多线程能满足程序猿编写很有效率的程序来达到充分利用CPU的目的,由于CPU的空暇时间可以保持在最低限度.有效利用多线程的关键是理解程序是并发运行而不是串行运行的.比如:程序中有两个子系统须要并发运行, ...

  6. 微信小程序从零开始开发步骤(一)

    从零到有写一个小程序系列专题,很早以前就想写来分享,但由于项目一直在进展,没有过多的时间研究技术,现在可以继续分享了.1:注册用没有注册过微信公众平台的邮箱注册一个微信公众号, 申请帐号 ,点击 ht ...

  7. 小强的HTML5移动开发之路(37)——jqMobi快速入门

    在<小强的HTML5移动开发之路(33)-- jqMobi基础>中我们了解了什么是jqMobi,并从官方下载了jqMobi开发包,下载后解压目录如下: 拷贝上面的/css目录./plugi ...

  8. SignalR+NAudio实现语音会话[WPF]

    原文:SignalR+NAudio实现语音会话[WPF] 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/lordwish/article/detai ...

  9. XML 标准诞生 20 周年:这个世界,它无处不在

    可扩展标记语言(XML)于 1998 年 2 月 10 日成为 W3C 的推荐标准.昨天,2018 年 2 月 10 日恰好是 W3C 推出的 XML 标准发布 20 周年纪念日.可点此查看原始的新闻 ...

  10. BZOJ 1509 逃学的小孩 - 树型dp

    传送门 题目大意: 在一棵树中, 每条边都有一个长度值, 现要求在树中选择 3 个点 X.Y. Z , 满足 X 到 Y 的距离不大于 X 到 Z 的距离, 且 X 到 Y 的距离与 Y 到 Z 的距 ...