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

很早以前就想写介绍WPF控件样式的系列文章,等啊等,等到AI也出来了。

最近终于也是沉下心来写这样一系列文章了。

我们直接进入正题。

 

在阅读本系列文章前需要你对WPF的样式和模板功能有一定的了解,如果还不熟悉样式和模板功能,可以访问以下链接

https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/controls/styles-templates-overview

还可以参考以下示例代码

https://github.com/Microsoft/WPF-Samples/tree/main/Styles%20&%20Templates/IntroToStylingAndTemplating

 

如何通过Blend获取控件的默认样式

安装Visual Studio时,只要钩选了.NET桌面开发,就会安装Blend组件

通过Blend组件,我们可以快速获取控件的默认样式。

image

 

开始菜单搜索并启动Blend

image

 

创建一个WPF项目,并放置一个Button控件

1     <Grid>
2         <Button Content="Button" HorizontalAlignment="Left" Margin="388,172,0,0" VerticalAlignment="Top" Height="63" Width="129" Background="Pink"/>
3     </Grid>

 

然后在对象和时间线窗口上选择这个Button,右键选择编辑模板-编辑副本

image

 

这里可以选择新建一个资源字典 ,点击 确定

image

 

这个时候我们就可以看到Button控件的默认样式和模板

Dictionary1.xaml

 1 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 2                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 3     
 4     <Style x:Key="FocusVisual">
 5         <Setter Property="Control.Template">
 6             <Setter.Value>
 7                 <ControlTemplate>
 8                     <Rectangle Margin="2" StrokeDashArray="1 2" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" SnapsToDevicePixels="true" StrokeThickness="1"/>
 9                 </ControlTemplate>
10             </Setter.Value>
11         </Setter>
12     </Style>
13     <SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
14     <SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
15     <SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
16     <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
17     <SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
18     <SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
19     <SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
20     <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
21     <SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
22     <Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
23         <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
24         <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
25         <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
26         <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
27         <Setter Property="BorderThickness" Value="1"/>
28         <Setter Property="HorizontalContentAlignment" Value="Center"/>
29         <Setter Property="VerticalContentAlignment" Value="Center"/>
30         <Setter Property="Padding" Value="1"/>
31         <Setter Property="Template">
32             <Setter.Value>
33                 <ControlTemplate TargetType="{x:Type Button}">
34                     <Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
35                         <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
36                     </Border>
37                     <ControlTemplate.Triggers>
38                         <Trigger Property="IsDefaulted" Value="true">
39                             <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
40                         </Trigger>
41                         <Trigger Property="IsMouseOver" Value="true">
42                             <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
43                             <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
44                         </Trigger>
45                         <Trigger Property="IsPressed" Value="true">
46                             <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
47                             <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
48                         </Trigger>
49                         <Trigger Property="IsEnabled" Value="false">
50                             <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
51                             <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
52                             <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
53                         </Trigger>
54                     </ControlTemplate.Triggers>
55                 </ControlTemplate>
56             </Setter.Value>
57         </Setter>
58     </Style>
59 </ResourceDictionary>

 

如何通过代码获取控件的默认模板

在前面的文章中,我介绍过这种方式

https://www.cnblogs.com/zhaotianff/p/8108151.html

使用下面的代码替换默认MainWindow.xaml.cs的代码即可

 1 public partial class MainWindow : Window
 2     {
 3         ListBox lbox;
 4         TextBox tbox;
 5         Grid grid;
 6         public MainWindow()
 7         {
 8             InitializeComponent();
 9             InitializeControl();
10             LoadControlTemplate();
11 
12         }
13 
14         /// <summary>
15         /// 创建界面
16         /// </summary>
17         private void InitializeControl()
18         {
19             grid = new Grid();
20             ColumnDefinition col1 = new ColumnDefinition();
21             ColumnDefinition col2 = new ColumnDefinition();
22             col1.Width = GridLength.Auto;
23             grid.ColumnDefinitions.Add(col1);
24             grid.ColumnDefinitions.Add(col2);
25 
26             //List
27             lbox = new ListBox();
28             lbox.SelectionChanged += (a, b) => { ShowControlTemplate(); };
29             //TextBox
30             tbox = new TextBox();
31             tbox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
32             tbox.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
33 
34             grid.Children.Add(lbox);
35             grid.Children.Add(tbox);
36 
37             Grid.SetColumn(lbox, 0);
38             Grid.SetColumn(tbox, 1);
39 
40             this.Content = grid;
41         }
42 
43         private void LoadControlTemplate()
44         {
45             Type type = typeof(System.Windows.Controls.Control);
46             List<Type> controlType = new List<Type>();
47             System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(System.Windows.Controls.Control));
48 
49             foreach (Type item in assembly.GetTypes())
50             {
51                 if (item.IsSubclassOf(type) && !item.IsAbstract && item.IsPublic)
52                 {
53                     controlType.Add(item);
54                 }
55             }
56             lbox.ItemsSource = controlType;
57         }
58 
59         private void ShowControlTemplate()
60         {
61             try
62             {
63                 Type type = (Type)lbox.SelectedItem;
64                 System.Reflection.ConstructorInfo info = type.GetConstructor(Type.EmptyTypes);
65                 Control control = (Control)info.Invoke(null);
66                 control.Visibility = Visibility.Collapsed;
67                 grid.Children.Add(control);
68                 ControlTemplate template = control.Template;
69 
70                 System.Xml.XmlWriterSettings setting = new System.Xml.XmlWriterSettings();
71                 setting.Indent = true;
72                 StringBuilder sb = new StringBuilder();
73                 System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(sb, setting);
74                 System.Windows.Markup.XamlWriter.Save(template, writer);
75                 tbox.Text = sb.ToString();
76                 grid.Children.Remove(control);
77 
78             }
79             catch (Exception ex)
80             {
81                 tbox.Text = ex.Message;
82             }
83         }
84     }

 

拆解Button样式和模板

1、首先我们看到资源定义部分,这部分主要是定义控件样式里用到的画刷

1 <SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
2 <SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
3 <SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
4 <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
5 <SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
6 <SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
7 <SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
8 <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
9 <SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>

 

2、然后就是默认样式的属性设置部分,这部分也不用过多介绍。

如果对于某个属性不了解的,可以直接查看Button控件的官方文档

https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/controls/button

 1 <Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
 2     <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
 3     <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
 4     <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
 5     <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
 6     <Setter Property="BorderThickness" Value="1"/>
 7     <Setter Property="HorizontalContentAlignment" Value="Center"/>
 8     <Setter Property="VerticalContentAlignment" Value="Center"/>
 9     <Setter Property="Padding" Value="1"/>
10 </Style>

 

3、接下来就是Button控件的样式的核心部分,Button的控件模板

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type Button}">
            <Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
                <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </Border>
        </ControlTemplate>
    </Setter.Value>
</Setter>

 

Button控件的模板比较简单,就是在一个Border里嵌套了一个ContentPresenter元素

image

 

image

 

 

这里我们详细介绍一下ContentPresenter这个元素

在前面的文章中,我介绍过WPF中的内容控件

https://www.cnblogs.com/zhaotianff/p/13608111.html

Label、Button、TabItem等都是内容控件

ContentPresenter类就是用于显示 ContentControl内容的类

严格意义上来说,ContentPresenter并不是最终的呈现类,它类似于一个外壳,真正显示内容时,它实际的逻辑如下:

1. 如果设置了ContentPresenter上的ContentTemplate属性,ContentPresenter会将该DataTemplate应用到Content属性,随后呈现生成的UIElement及其子元素(如果有)

2. 如果设置了ContentPresenter上的ContentTemplateSelector属性,ContentPresenter会选用匹配的DataTemplate应用到Content属性,随后呈现生成的UIElement及其子元素(如果有)。

关于控件模板选择器可以参考:https://www.cnblogs.com/zhaotianff/p/18380995

3. 如果存在与Content的类型关联的DataTemplateContentPresenter会将该DataTemplate应用到Content属性,随后呈现生成的`UIElement`及其子元素(如果有)。

4. 如果ContentUIElement对象,则直接显示该UIElement。若该UIElement已存在父元素,将抛出异常。

5. 如果存在可将Content类型转换为UIElementTypeConverterContentPresenter会使用该类型转换器,并显示转换后得到的UIElement

6. 如果存在可将Content类型转换为字符串的TypeConverterContentPresenter会使用该类型转换器,并创建一个TextBlock承载该字符串,显示此TextBlock

7. 如果内容为XmlElement,会在TextBlock中显示其InnerText属性的值。

8. ContentPresenter会对Content调用ToString方法,创建TextBlock承载该方法返回的字符串,并显示该TextBlock

 

4、然后就是一些设置状态的触发器

 1  <ControlTemplate.Triggers>
 2      <!--默认状态-->
 3      <Trigger Property="IsDefaulted" Value="true">
 4          <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
 5      </Trigger>
 6      <!--鼠标划过状态-->
 7      <Trigger Property="IsMouseOver" Value="true">
 8          <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
 9          <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
10      </Trigger>
11      <!--鼠标按下状态-->
12      <Trigger Property="IsPressed" Value="true">
13          <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
14          <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
15      </Trigger>
16      <!--启用状态-->
17      <Trigger Property="IsEnabled" Value="false">
18          <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
19          <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
20          <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
21      </Trigger>
22  </ControlTemplate.Triggers>

 

一个扁平化风格的按钮样式和模板案例

源码来自:https://github.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers.Net40/Themes/Theme.xaml  (欢迎大家使用WPFDevelopers控件库)

 1 <SolidColorBrush x:Key="WD.PrimaryBrush" Color="#409EFF" />
 2 <SolidColorBrush x:Key="WD.PrimaryMouseOverBrush" Color="#EBF4FF" />
 3 <SolidColorBrush x:Key="WD.BackgroundBrush" Color="#FFFFFF" />
 4 <SolidColorBrush x:Key="WD.BaseBrush" Color="#DCDFE6" />
 5 <SolidColorBrush x:Key="WD.RegularTextBrush" Color="#606266" />
 6 <SolidColorBrush x:Key="WD.WindowTextBrush" Color="#FFFFFF" />
 7 
 8 <Style x:Key="WD.DefaultButton" TargetType="{x:Type Button}">
 9     <Setter Property="FocusVisualStyle" Value="{x:Null}" />
10     <Setter Property="FrameworkElement.OverridesDefaultStyle" Value="True" />
11     <Setter Property="HorizontalContentAlignment" Value="Center" />
12     <Setter Property="VerticalContentAlignment" Value="Center" />
13     <Setter Property="BorderThickness" Value="1" />
14     <Setter Property="Cursor" Value="Hand" />
15     <Setter Property="Background" Value="{DynamicResource WD.BackgroundBrush}" />
16     <Setter Property="BorderBrush" Value="{DynamicResource WD.BaseBrush}" />
17     <Setter Property="Foreground" Value="{DynamicResource WD.RegularTextBrush}" />
18     <Setter Property="Template">
19         <Setter.Value>
20             <ControlTemplate TargetType="{x:Type Button}">
21                 <Border x:Name="PART_Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1" SnapsToDevicePixels="True" >
22                     <ContentPresenter x:Name="PART_ContentPresenter" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True" TextElement.Foreground="{TemplateBinding Foreground}" />
23                 </Border>
24                 <ControlTemplate.Triggers>
25                     <Trigger Property="IsFocused" Value="True">
26                         <Setter TargetName="PART_Border" Property="UIElement.Opacity" Value=".9" />
27                     </Trigger>
28                     <Trigger Property="IsPressed" Value="True">
29                         <Setter Property="BorderBrush" Value="{DynamicResource WD.PrimaryBrush}" />
30                         <Setter Property="Background" Value="{DynamicResource WD.PrimaryMouseOverBrush}" />
31                         <Setter Property="Foreground" Value="{DynamicResource WD.PrimaryBrush}" />
32                     </Trigger>
33                     <Trigger Property="IsMouseOver" Value="True">
34                         <Setter Property="BorderBrush" Value="{DynamicResource WD.PrimaryBrush}" />
35                         <Setter Property="Background" Value="{DynamicResource WD.PrimaryMouseOverBrush}" />
36                         <Setter Property="Foreground" Value="{DynamicResource WD.PrimaryBrush}" />
37                     </Trigger>
38                 </ControlTemplate.Triggers>
39             </ControlTemplate>
40         </Setter.Value>
41     </Setter>
42 </Style>

 

这个样式是在原生样式的基础上改变了一些配色,理解起来并不困难。

核心的控件模板如下:

1 <Border x:Name="PART_Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1" SnapsToDevicePixels="True" >
2      <ContentPresenter x:Name="PART_ContentPresenter" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True" TextElement.Foreground="{TemplateBinding Foreground}" />
3 </Border>

 

通过触发器控制各状态下的显示效果

 1 <ControlTemplate.Triggers>
 2     <!--焦点状态-->
 3     <Trigger Property="IsFocused" Value="True">
 4         <Setter TargetName="PART_Border" Property="UIElement.Opacity" Value=".9" />
 5     </Trigger>
 6     <!--鼠标按下状态-->
 7     <Trigger Property="IsPressed" Value="True">
 8         <Setter Property="BorderBrush" Value="{DynamicResource WD.PrimaryBrush}" />
 9         <Setter Property="Background" Value="{DynamicResource WD.PrimaryMouseOverBrush}" />
10         <Setter Property="Foreground" Value="{DynamicResource WD.PrimaryBrush}" />
11     </Trigger>
12     <!--鼠标划过状态-->
13     <Trigger Property="IsMouseOver" Value="True">
14         <Setter Property="BorderBrush" Value="{DynamicResource WD.PrimaryBrush}" />
15         <Setter Property="Background" Value="{DynamicResource WD.PrimaryMouseOverBrush}" />
16         <Setter Property="Foreground" Value="{DynamicResource WD.PrimaryBrush}" />
17     </Trigger>
18 </ControlTemplate.Triggers>

 

运行效果如下:

demo

 

使用VisualState为Button增加动画效果

在前面的文章中,我介绍过WPF里控件的VisualState功能

如果对这一块的功能不了解,可以访问以下链接:https://www.cnblogs.com/zhaotianff/p/13254430.html

Button控件提供的VisualState如下 

VisualState名称VisualStateGroup名称Description
Normal CommonStates 默认状态
MouseOver CommonStates 鼠标划过状态
Pressed CommonStates 鼠标按下状态
Disabled CommonStates 禁用状态
Focused FocusStates 焦点状态
Unfocused FocusStates 失去焦点状态
Valid ValidationStates 该控件使用了Validation类,且Validation.HasError附加属性为false。
InvalidFocused ValidationStates Validation.HasError 附加属性为 true,且该控件具有焦点。
InvalidUnfocused ValidationStates Validation.HasError 附加属性为 true,且该控件未获得焦点。

 

我们来看一下如何使用,完整示例代码如下:

 1     <Style x:Key="WD.WindowButtonStyle" TargetType="{x:Type Button}">
 2         <Setter Property="Foreground" Value="#303133" />
 3         <Setter Property="Padding" Value="3" />
 4         <Setter Property="Margin" Value="0" />
 5         <Setter Property="MinWidth" Value="30" />
 6         <Setter Property="MinHeight" Value="28" />
 7         <Setter Property="BorderThickness" Value="1" />
 8         <Setter Property="Background" Value="White"></Setter>
 9         <Setter Property="Template">
10             <Setter.Value>
11                 <ControlTemplate TargetType="{x:Type Button}">
12                     <Border Background="{TemplateBinding Background}" x:Name="Border">
13                         <ContentPresenter x:Name="PART_ContentPresenter" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" Opacity="0.7" />
14                         <VisualStateManager.VisualStateGroups>
15                             <VisualStateGroup x:Name="CommonStates">
16                                 <!--默认状态-->
17                                 <VisualState x:Name="Normal">
18                                     <Storyboard>
19                                         <ColorAnimation Storyboard.TargetName="Border" Storyboard.TargetProperty="Background.Color" To="White"/>
20                                         <ColorAnimation Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)" To="#606266"/>
21                                     </Storyboard>
22                                 </VisualState>
23                                 <!--鼠标划过状态-->
24                                 <VisualState x:Name="MouseOver">
25                                     <Storyboard>
26                                         <ColorAnimation Storyboard.TargetName="Border" Storyboard.TargetProperty="Background.Color" To="#409EFF"/>
27                                         <ColorAnimation Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)" To="White"/>
28                                     </Storyboard>
29                                 </VisualState>
30                             </VisualStateGroup>
31                         </VisualStateManager.VisualStateGroups>
32                     </Border>
33                 </ControlTemplate>
34             </Setter.Value>
35         </Setter>
36     </Style>

 

这里我只增加了Normal和MouseOver两种状态(其它状态可自行添加),并使用了两个ColorAnimation对背景和文字颜色进行动画

 1 <VisualStateManager.VisualStateGroups>
 2     <VisualStateGroup x:Name="CommonStates">
 3         <!--默认状态-->
 4         <VisualState x:Name="Normal">
 5             <Storyboard>
 6                 <!--背景颜色动画-->
 7                 <ColorAnimation Storyboard.TargetName="Border" Storyboard.TargetProperty="Background.Color" To="White"/>
 8                 <!--文字颜色动画-->
 9                 <ColorAnimation Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)" To="#606266"/>
10             </Storyboard>
11         </VisualState>
12         <!--鼠标划过状态-->
13         <VisualState x:Name="MouseOver">
14             <Storyboard>
15                 <!--背景颜色动画-->
16                 <ColorAnimation Storyboard.TargetName="Border" Storyboard.TargetProperty="Background.Color" To="#409EFF"/>
17                  <!--文字颜色动画-->
18                 <ColorAnimation Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)" To="White"/>
19             </Storyboard>
20         </VisualState>
21     </VisualStateGroup>
22 </VisualStateManager.VisualStateGroups>

 

运行效果如下:

demo

 

示例代码:

https://github.com/zhaotianff/cnblog-demo-code/tree/main/WPFStyleAndTemplateDemo

 

参考资料:

.net - What's the difference between ContentControl and ContentPresenter? - Stack Overflow

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