WPF之UI进阶--控件样式与样式模板及词典

WPF的优势之一就是能够更加容易快捷的对窗体和控件的外面进行改造,换句话说,那就是UI设计个性化更加容易。主要是借助了样式、模板及词典来实现的。那么本篇博文就一一对他们进行介绍。

文章目录

文章原出处: 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

相关推荐
SoraLuna3 小时前
「Mac畅玩鸿蒙与硬件28」UI互动应用篇5 - 滑动选择器实现
macos·ui·harmonyos
.net开发7 小时前
WPF怎么通过RestSharp向后端发请求
前端·c#·.net·wpf
九鼎科技-Leo7 小时前
WPF 中 NavigationWindow 与 Page 的继承关系解析
wpf
SongYuLong的博客8 小时前
C# WPF 打印机
wpf
就是有点傻8 小时前
WPF中的转换器
wpf
martian66514 小时前
QT开发:掌握现代UI动画技术:深入解析QML和Qt Quick中的动画效果
开发语言·c++·qt·ui
.net开发15 小时前
WPF使用prism框架发布订阅实现消息提示
c#·.net·wpf
初九之潜龙勿用16 小时前
C#结合JS解决Word添加无效位图导致进程停滞的问题
javascript·ui·c#·word·asp.net
职创未来官方17 小时前
大话C++:第26篇 类模板
c++·面向对象·模板·模板类·嵌入式物联网·隐式实例化·显示实例化
那少年已不再......19 小时前
C#WPF使用CommunityToolkit.Mvvm库
开发语言·c#·wpf