WPF的优势之一就是能够更加容易快捷的对窗体和控件的外面进行改造,换句话说,那就是UI设计个性化更加容易。主要是借助了样式、模板及词典来实现的。那么本篇博文就一一对他们进行介绍。
文章目录
- 一、样式
-
- [1: 定义样式](#1: 定义样式)
- [2: 使用Setter设置属性](#2: 使用Setter设置属性)
- [3: 应用触发器(可选)](#3: 应用触发器(可选))
- 4:带属性的setter和style.triggle标签中的setter
- 5:高级货ControlTemplate
- 5:绘图属性
- 二、模板
-
- [1. 定义控件模板(ControlTemplate)](#1. 定义控件模板(ControlTemplate))
- [2. 创建样式(Style)](#2. 创建样式(Style))
- [3. 应用样式和模板](#3. 应用样式和模板)
- 4、另外一种方式:在模板中直接定义好样式
- 三、词典
文章原出处: https://blog.csdn.net/haigear/article/details/142632573
首先我们来看看通过简单修改而得到的这么一个控件效果,如下图,我们对radiobutton、checkbox、button进行了改造:
由于录屏软件无法录到鼠标的点击,所以大家看到的就是突然的控件操作。
最左边的实际是radiobutton,我们将圆形按钮修改为带字母的按钮,这个改造很适合做考试系统的选择题的项目中。
没有对控件进行改造之前,效果是这样的,大家可以对比一下:
文章原出处: https://blog.csdn.net/haigear/article/details/142632573
一、样式
样式的实现和我们在web前端做css其实差不多的,只不过这里采用了xaml,也就是xml的一种标签语言来实现。
在WPF中,创建并应用样式(Style)通常涉及以下步骤,这里以在定义在窗口级别Window.Resources中,这样整个窗体中所有的对应的目标控件都有效,如果定义在应用程序级别<Application.Resources>,那就对于整个应用程序中的目标控件都有效。下面我们来看如何定义样式。
1: 定义样式
在Window.Resources中定义样式,指定TargetType为要应用样式的控件类型。我们需要给哪种控件写样式那这里的TargetType的值就些什么类型的控件,比如:
csharp
<Style TargetType="{x:Type CheckBox}">
csharp
<Style TargetType="{x:Type RadioButton}">
csharp
<Style TargetType="{x:Type Button}">
2: 使用Setter设置属性
通过Setter元素为控件的属性设置默认值。每个Setter包含Property和Value属性。比如,这里我们就修改了控件的背景和前景以及字体大小background,foreground、fontsize。
csharp
<Setter Property="Background" Value="LightGray"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontSize" Value="16"/> <Setter Property="Padding" Value="10"/>
记住每种控件的属性都必须使用一个setter配合property、value来实现。
关于Property和Value
从上面的代码可知,wpf的样式中我们使用setter中的property来指定修改控件的相应属性,直接写在setter标签内。很自然和属性对应的值就用value来表达了。
关于<Setter.Value>
当要设置的Value比较复杂时,例如设置一个模板或者一个复杂对象时,会使用<Setter.Value>这种嵌套的形式,但它仍然是标签的一部分。例如:
xml
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<!-- 这里是模板的定义 -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
在这个例子中,<Setter.Value>是在标签内部,用于指定Template属性的值(这里是一个ControlTemplate)。它不是一个独立于的标签,而是用于处理复杂属性值设置的一种嵌套语法结构。
3: 应用触发器(可选)
如果需要根据控件的状态改变样式,可以使用Style.Triggers定义一个或多个Trigger。每个Trigger可以包含一个或多个Setter,这些Setter仅在触发器条件满足时应用。
csharp
<Style.Triggers>
<!-- 鼠标悬停时改变背景色 -->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray"/>
</Trigger>
<!-- 按钮被按下时改变前景色 -->
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
从上面的代码实例中我们可以发现,每个Trigger标签的子标签可以是Setter标签,也就是说,Trigger可以用来修改控件的属性。
注意事项:
确保TargetType正确指向你想要应用样式的控件类型。
Setter的Property属性必须是目标类型的一个依赖属性。
Style.Triggers中的Trigger可以基于控件的属性值变化或状态变化(如IsMouseOver、IsChecked等)来触发。可以理解为类似于监听变化的作用。
如果样式定义在Window.Resources中,它将自动应用于所有匹配TargetType的控件。如果需要对特定控件应用不同的样式,可以使用StaticResource显式引用样式。
以下是一个在Window.Resources中定义按钮样式的示例,包括Setter和Style.Triggers的使用:
xml
<Window x:Class="YourNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<!-- 定义按钮样式 -->
<Style TargetType="{x:Type Button}">
<!-- 设置按钮的默认属性 -->
<Setter Property="Background" Value="LightGray"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Padding" Value="10"/>
<!-- 应用触发器 -->
<Style.Triggers>
<!-- 鼠标悬停时改变背景色 -->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray"/>
</Trigger>
<!-- 按钮被按下时改变前景色 -->
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<!-- 应用样式到按钮 -->
<Button Content="Click Me" Style="{StaticResource {x:Type Button}}"/>
</Window>
在这个例子中:
我们定义了一个针对Button类型的样式,并设置了按钮的默认背景色、前景色、字体大小和内边距。
使用Style.Triggers定义了两个触发器:一个用于鼠标悬停时改变背景色,另一个用于按钮被按下时改变前景色。
最后,我们在Button控件上通过Style属性应用了这个样式。
通过这种方式,你可以为WPF应用程序中的按钮定制外观,并根据用户的交互动态改变样式
4:带属性的setter和style.triggle标签中的setter
两者都是用于设置属性值的。无论是在Style标签下的普通Setter还是在Style.Triggers中的Setter,其最终目的都是改变某个控件的属性值,以达到改变控件外观或行为的效果。但他们还是有所不同。
触发条件
普通 Setter:在Style中的普通Setter会在样式应用到控件时无条件地设置属性值。只要控件使用了这个样式,对应的属性就会被设置为Setter中指定的值。例如,上面的第一个例子中,只要按钮应用了MyButtonStyle样式,其背景色就会被设置为蓝色。
Style.Triggers 中的 Setter:只有在满足特定的触发条件时才会设置属性值。在上面的第二个例子中,只有当鼠标悬停在按钮上(IsMouseOver = "True")这个触发条件满足时,按钮的背景色才会被设置为黄色。
灵活性和动态性
普通 Setter:相对固定,一旦样式应用到控件,属性值就固定下来(除非有其他机制修改它,如数据绑定等)。它主要用于设置控件的初始外观或默认状态下的属性值。
Style.Triggers 中的 Setter:更具动态性,可以根据控件的状态变化(如鼠标交互、数据变化等)来改变属性值,从而提供更丰富的用户交互体验。例如,可以根据按钮是否被按下、是否获得焦点等不同状态动态地改变按钮的颜色、大小等属性。
应用范围
普通 Setter:通常用于设置一些基本的、不依赖于动态状态变化的属性。例如,设置按钮的字体、字号、默认背景色等基本属性。
Style.Triggers 中的 Setter:专注于处理与特定触发条件相关的属性设置,如响应鼠标事件(悬停、按下等)、数据验证结果(如数据错误时改变控件外观)等情况下的属性调整。
5:高级货ControlTemplate
ControlTemplate用于定义控件的可视化结构。它允许你完全自定义控件的外观,覆盖控件的默认视觉呈现。例如,你可以使用ControlTemplate来重新定义一个Button看起来像一个圆形图标,而不是默认的矩形按钮。
ControlTemplate定义了控件的整体视觉结构,而ContentPresenter是这个结构中的一部分,专门负责显示控件的内容。ControlTemplate可以包含各种元素来构建控件的外观,如Border、Grid、Ellipse等,ContentPresenter则确保控件原本的内容(如Button的文本或ComboBox的下拉选项等)能够正确地在这个自定义的视觉结构中显示。
ContentPresenter
ContentPresenter是一个在ControlTemplate中非常重要的元素,可以说是关键元素。没有它就无法在自定义的控件模板(ControlTemplate)中呈现控件的内容。例如,对于一个Button控件,其Content(可能是文本或者图标等)就是通过ContentPresenter在自定义模板中显示出来的。
在ControlTemplate中,通常会将ContentPresenter放置在合适的位置,以确定内容显示的位置。我们通常都会将它置于装饰容器Border内,例如:
xml
<ControlTemplate TargetType="Button">
<Border BorderBrush="Black" BorderThickness="1">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
获取外部资源TemplateBinding
TemplateBinding可以用于在ControlTemplate中绑定属性到外部的源。例如,当自定义Button模板时,可以使用TemplateBinding将Button的某些属性与模板内部的元素相关联。对于ContentPresenter,如果想要根据外部Button的属性来调整内容的显示方式,可以使用TemplateBinding。
假设想要根据Button的Foreground属性来设置ContentPresenter中的内容颜色,可以这样做
xml
<ControlTemplate TargetType="Button">
<Border BorderBrush="Black" BorderThickness="1">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{TemplateBinding Foreground}"/>
</Border>
</ControlTemplate>
在ControlTemplate中,TemplateBinding是一种在模板内部元素和外部控件属性之间建立联系的方式。它使得模板可以根据外部控件的状态或属性进行自适应调整。
在了解完样式后,模板和样式词典就很容易了。
5:绘图属性
上面代码中有的用到了一些绘图属性如rectangle.fill,这里将一些常用的绘图属性列表如下,供初学者查阅。
属性 | 作用 | 用法示例 |
---|---|---|
Fill | 指定图形内部区域的填充内容,可以是颜色、渐变或图案等 | <Rectangle Width="100" Height="50"><Rectangle.Fill><SolidColorBrush Color="Blue"/></Rectangle.Fill></Rectangle> |
Stroke | 定义图形轮廓(边框)的颜色 | <Rectangle Width="100" Height="50"><Rectangle.Stroke><SolidColorBrush Color="Black"/></Rectangle.Stroke><Rectangle.StrokeThickness>2</Rectangle.StrokeThickness></Rectangle> |
StrokeThickness | 指定图形轮廓(描边)的宽度 | <Rectangle Width="100" Height="50"><Rectangle.Stroke><SolidColorBrush Color="Black"/></Rectangle.Stroke><Rectangle.StrokeThickness>2</Rectangle.StrokeThickness></Rectangle> |
Opacity | 控制图形的透明度,取值范围0 - 1 | <Rectangle Width="100" Height="50"><Rectangle.Fill><SolidColorBrush Color="Blue"><SolidColorBrush.Opacity>0.5</SolidColorBrush.Opacity></SolidColorBrush></Rectangle.Fill></Rectangle> |
CornerRadius | 将矩形的角变为圆角,可统一指定或分别指定四个角的半径 | <Rectangle Width="100" Height="50" CornerRadius="10"><Rectangle.Fill><SolidColorBrush Color="Green"/></Rectangle.Fill></Rectangle> |
Width | 指定图形的宽度 | <Rectangle Width="100" Height="50"><Rectangle.Fill><SolidColorBrush Color="Red"/></Rectangle.Fill></Rectangle> |
Height | 指定图形的高度 | <Rectangle Width="100" Height="50"><Rectangle.Fill><SolidColorBrush Color="Red"/></Rectangle.Fill></Rectangle> |
RenderTransform | 对图形进行平移、旋转、缩放等变换操作,常见变换类型有TranslateTransform、RotateTransform、ScaleTransform等 | <Rectangle Width="100" Height="50"><Rectangle.RenderTransform><TranslateTransform X = "20" Y = "30"/></Rectangle.RenderTransform><Rectangle.Fill><SolidColorBrush Color="Yellow"/></Rectangle.Fill></Rectangle> |
Clip | 用于裁剪图形的显示区域,可使用几何形状定义裁剪区域 | <Rectangle Width="100" Height="50"><Rectangle.Clip><EllipseGeometry Center="50,25" RadiusX="30" RadiusY="20"/></Rectangle.Clip><Rectangle.Fill><SolidColorBrush Color="Purple"/></Rectangle.Fill></Rectangle> |
Stretch(针对可拉伸图形如Image等) | 确定当图形尺寸与容器尺寸不匹配时如何调整图形大小,取值有None、Fill、Uniform、UniformToFill等 | <Image Source="myImage.jpg" Stretch="Uniform"/> |
文章原出处:https://blog.csdn.net/haigear/article/details/142632573
二、模板
在 WPF 中,样式(Style)和控件模板(ControlTemplate)是定义控件外观和行为的关键工具。样式通常用于设置控件的属性,而控件模板则用于定义控件的结构和布局。编写样式模板的步骤:
1. 定义控件模板(ControlTemplate)
控件模板允许你完全自定义控件的视觉结构。你可以通过 ControlTemplate 元素定义控件的外观和行为。
步骤 1: 定义控件模板
xml
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<!-- 定义触发器,例如当按钮被按下时改变背景 -->
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Background" Value="LightGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
在这个模板中,我们定义了一个按钮的外观,使用 Border 和 ContentPresenter 来布局按钮的背景和内容。我们还定义了一个触发器,当按钮被按下时改变背景色。
2. 创建样式(Style)
样式用于封装控件的属性设置和模板。样式可以包含 Setter 元素来设置属性,以及 ControlTemplate 来定义控件的外观。
步骤 2: 创建样式
xml
<Style TargetType="{x:Type Button}">
<Setter Property="Template" Value="{DynamicResource YourButtonTemplate}"/>
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="16"/>
</Style>
在这个样式中,我们引用了上面定义的控件模板,并设置了按钮的默认背景、前景色和字体大小。
3. 应用样式和模板
将样式应用到控件上,可以通过 Style 属性直接应用,或者通过资源字典(ResourceDictionary)引用。
假设我们想要自定义一个按钮的外观和行为,以下是具体的步骤和代码示例:
步骤 3: 应用样式
xml
<Window x:Class="YourNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="200">
<Window.Resources>
<!-- 在这里定义控件模板和样式 -->
<ControlTemplate x:Key="YourButtonTemplate" TargetType="{x:Type Button}">
<!-- 控件模板定义 -->
</ControlTemplate>
<Style TargetType="{x:Type Button}">
<!-- 样式定义 -->
</Style>
</Window.Resources>
<Grid>
<!-- 应用样式到按钮 -->
<Button Content="Click Me" Style="{DynamicResource {x:Type Button}}"/>
</Grid>
</Window>
在这个示例中,我们使用的思路是在模板中定义我们需要的样式效果,然后通过样式style标签的定义引用template,最后在控件中引用style的动态资源。我们在 Window.Resources 中定义了控件模板和样式,并通过 DynamicResource 引用了模板和样式。然后,我们在 Button 控件上应用了这个样式。
4、另外一种方式:在模板中直接定义好样式
也就是说,我们不必像上述步骤那么麻烦,直接一点,把要设置的样式先在模板中实现了即可。
xml
<ControlTemplate x:Key="ButtonTemplate TargetType="{x:Type Button}">
<Border BorderBrush="Orange" BorderThickness="3" CornerRadius="2" Background="Red">
<ContentPresenter Margin="{TemplateBinding Padding}" HorizontalAlignment="Center" />
</Border>
</ControlTemplate>
ContentPresenter 和templateBinding前面讲样式定义的时候已经讲过了,不熟悉的可以爬楼上去看看。
下面是应用模板的调用:
xml
<StackPanel Margin="5" >
<Button Margin="5" Padding="13">Normal Button</Button>
<Button Margin="5" Padding="3" Template="{StaticResource ButtonTemplate}" />
</StackPanel>
通过这种方式,你可以完全控制 WPF 控件的外观和行为,实现高度定制化的用户界面。
文章原出处:https://blog.csdn.net/haigear/article/details/142632573
三、词典
在 WPF 中,样式和控件模板通常定义在资源字典(ResourceDictionary)中,以便于重用和管理。样式词典可以看作是资源字典的一种应用,用于集中管理样式。
如何编写样式词典?样式词典的编写通常涉及以下步骤:
1.创建资源字典文件:
创建一个或多个 XAML 文件(通常是 .xaml 文件),用于存放样式和资源定义。
假设我们有两个资源字典文件,一个用于定义按钮样式,另一个用于定义窗口的背景样式。ButtonStyles.xaml和WindowStyles.xaml;
2.定义样式和模板:
在资源字典中定义样式和控件模板,就像之前示例中展示的那样。
ButtonStyles.xaml
xml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="PrimaryButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Blue"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="14"/>
<!-- 更多设置 -->
</Style>
</ResourceDictionary>
WindowStyles.xaml
xml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="MainWindowStyle" TargetType="{x:Type Window}">
<Setter Property="Background" Value="LightGray"/>
<!-- 更多设置 -->
</Style>
</ResourceDictionary>
3.引用资源字典:
在需要使用这些样式的 XAML 文件中,通过<ResourceDictionary.MergedDictionaries> 标签引入资源字典文件。
在主窗口中引用样式词典
xml
<Window x:Class="YourNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="200"
Style="{DynamicResource MainWindowStyle}">
<Grid>
<Button Content="Click Me" Style="{DynamicResource PrimaryButtonStyle}"/>
</Grid>
</Window>
在主窗口的 XAML 中,我们通过 <Window.Resources> 引入了 WindowStyles.xaml,并使用 DynamicResource 引用了窗口样式。同时,我们也在按钮上应用了 PrimaryButtonStyle 样式。
通过这种方式,你可以将样式和资源集中管理,并在多个地方重用它们,从而提高代码的可维护性和可扩展性。样式词典(资源字典)的使用有助于保持样式的一致性,并简化样式管理。
文章可能随时更新,请关注文章原出处:https://blog.csdn.net/haigear/article/details/142632573