WPF控件样式和模板全解析-Label控件

可能有些小伙伴觉得Label控件比较简单,不需要再单独介绍它的样式和模板。

这里呢,我还是觉得很有必要拿出来讲一下,通过剖析它的内部模板,来了解Label控件更深层次的原理。

 

Label控件的默认样式和模板

依旧是使用Blend获取默认的样式和模板,如下所示:

 1   <Style x:Key="LabelStyle1" TargetType="{x:Type Label}">
 2       <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
 3       <Setter Property="Background" Value="Transparent"/>
 4       <Setter Property="Padding" Value="5"/>
 5       <Setter Property="HorizontalContentAlignment" Value="Left"/>
 6       <Setter Property="VerticalContentAlignment" Value="Top"/>
 7       <Setter Property="Template">
 8           <Setter.Value>
 9               <ControlTemplate TargetType="{x:Type Label}">
10                   <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
11                       <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
12                   </Border>
13                   <ControlTemplate.Triggers>
14                       <Trigger Property="IsEnabled" Value="false">
15                           <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
16                       </Trigger>
17                   </ControlTemplate.Triggers>
18               </ControlTemplate>
19           </Setter.Value>
20       </Setter>
21   </Style>

 

拆解Button样式和模板

从上面的样式可以看到,Label控件的模板和Button控件几乎一样,都是Border里面套一个ContentPresenter控件

1  <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
2       <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
3 </Border>

 

然后就是一个触发器,用于设置禁用状态下Label控件文字的颜色

1 <ControlTemplate.Triggers>
2     <Trigger Property="IsEnabled" Value="false">
3          <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
4     </Trigger>
5 </ControlTemplate.Triggers>

 

Label和TextBlock的区别

一直就听说TextBlock是轻量级的文本显示控件,Label更重量级。

但是根据前面文章中,关于ContentPresenter控件的介绍就可以知道:ContentPresenter控件只是一个壳,在显示文本时最终还是使用的TextBlock控件。

那为什么还是会有这个说法呢?

原因有以下几个方面:

1、继承链不同,TextBlock的继承关系更简单,Label更复杂

  • TextBlock 直接继承自 FrameworkElement。它处于WPF元素体系的最底层,属于“呈现元素”,只负责把自己画在屏幕上。

  • Label 继承自 ContentControl,完整的继承关系是ContentControl->Control->FrameworkElement,而Control控件拥有更多的依赖属性及其它特性,所以它的开销就会大一点,相比之下,TextBlock的功能就更单一。

2、视觉树的层级深度

      TextBlock只有一层,而Label控件会有Label->Border->ContentPresenter->TextBlock多层。

      WPF的布局过程(Measure和Arrange)会递归遍历视觉树,所以每多一层嵌套,CPU就需要多做一次计算。

      通常情况下,对于单个Label影响不大,但是当数量比较多时,例如大量的ListBoxDataGrid列表项时,就会对性能造成一定的影响。

3、焦点处理开销

     Label默认Focusable=true,TextBlock默认Focusable=false,

     而且Label可以使用助记快捷键 AccessKey功能,例如下面的代码,按按下键盘上的Alt+H时,可以快速将光标定位至TextBox元素。

1  <StackPanel>
2      <Label  Content="_HelloWorld" Target="{Binding ElementName=tbox2}"></Label>
3      <TextBox x:Name="tbox2"></TextBox>
4  </StackPanel>

动画

 

4、布局计算问题

  • TextBlock 的测量逻辑较专一,只计算文字的宽高。

  • Label 属于内容控件,可以所以放置任意控件,如图片、布局面板等。这就导致在计算界面布局时,它的测量算法比TextBlock复杂。

 

posted @ 2026-08-27 21:51  zhaotianff  阅读(1)  评论(0)    收藏  举报