WPF高级教程(十六)样式

概念

样式是可以应用于元素的一系列属性值的集合。

样式期望使用一份xaml代码来设置一系列元素的细节,比如内外边距,字体颜色等。

样式类似于CSS但是要比CSS更加强大,强大之处在于:

  • 可以设置依赖项属性,使其可以控制控件行为
  • 支持触发器
  • 可以使用模板重新定义控件的内置外观

定义和设置样式

定义样式

<Window.Resources>
    <Style x:Key="BigFontButtonStyle">
        <Setter Property="Control.FontFamily" Value="Times New Roman"/>
        <Setter Property="Control.FontSize" Value="18"/>
        <Setter Property="Control.FontWeight" Value="Bold"/>
    </Style>
</Window.Resources>

设置样式

<Button x:Name="btn" Style="{StaticResource BigFontButtonStyle}">Test Button</Button>

通过代码设置样式

btn.Style = (Style)window.FindResource("BigFontButtonStyle");

设置样式

在上面最简单的例子中我们看到了Setter的使用方法,这一节我们详细看一下:

  • Setter只能使用在依赖项属性上
  • Setter不是只能设置字符串,也可以设置对象,需要用到下面的语法
    <Style x:Key="TestStyle">
        <Setter Property="Control.Background">
            <Setter.Value>
                <SolidColorBrush Color="Aquamarine"/>
            </Setter.Value>
        </Setter>
    </Style>
    
  • 如果上面的例子中这个画刷要被多次使用,可以定义为资源,下面的代码体现了这样的修改
    <SolidColorBrush x:Key="TestBrush" Color="Aquamarine"/>
    <Style x:Key="TestStyle">
        <Setter Property="Control.Background" Value="{StaticResource TestBrush}"/>
    </Style>
    

TargetType

我们在设置样式的时候,我们发现在写Property的时候,都是写Control.Background,这是告诉样式我们这个样式应用于Control,但是我们写多少个Setter就要写多少次Control,为了简化写法,我们推荐将对于一种类型控件的设置写到一个样式中并为其指定TargetType,这样可以简化代码

<Style TargetType="Button">
    <Setter Property="Background" Value="{StaticResource TestBrush}"/>
</Style>

如果在Style的属性上指定了TargetType,就不需要在Property中再每一次都指定应用于什么元素了。

样式的继承

样式的继承允许我们从一个样式中继承所有的设置,并且针对性的修改几个属性,需要使用BasedOn语法,我们看看其用法

<SolidColorBrush x:Key="TestBrush" Color="Aquamarine"/>
<Style x:Key="TestStyle">
    <Setter Property="Control.Background" Value="{StaticResource TestBrush}"/>
    <Setter Property="Control.FontWeight" Value="Bold"/>
</Style>
<Style x:Key="BaseStyle" BasedOn="{StaticResource TestStyle}">
    <Setter Property="Control.FontWeight" Value="Normal"/>
</Style>

如果按钮使用了 BaseStyle 其底色是从TestStyle继承而来的,但是其FontWeight是覆盖之后的Normal

我们需要注意的是:只在有大量样式相同,只有一点点不同需要改变的时候使用继承语法,否则继承语法带来的样式复杂性将使人得不偿失。慎用。

应用范围

之前我们都是使用x:Key来声明一个样式,如果不使用它,我们就需要注意样式的应用范围,我们记住下面两种原则

  • 完全不指明的样式不会被应用
    <!--不会被应用-->
    <Style>
        <Setter Property="Control.Background" Value="Red"/>
    </Style>
    
  • 只指明TargetType的样式为该控件在全局的默认样式
    <!--会被应用到有效范围内的所有按钮-->
    <Style TargetType="Button">
        <Setter Property="Control.Background" Value="Red"/>
    </Style>
    

然而,我们需要十分谨慎的使用全局默认样式,主要因为在实际的开发中,我们经常会嵌套控件(使用模板),在对于某个控件的样式设置可能会影响很多不需要影响的控件,而且,在开发过程中,突然出现的不知道来自于哪里的默认样式常常会让我们十分抓狂,所以除非是明确的全局字体等,不要使用基于控件类型的全局的样式。

样式清除

给样式赋值 {x:Null} 可以清除样式

<Window.Resources>
    <Style TargetType="Button">
        <Setter Property="Control.Background" Value="Red"/>
    </Style>
</Window.Resources>
<StackPanel>
    <Button x:Name="btn" Style="{x:Null}">Test Button</Button>
</StackPanel>

上面例子中,按钮使用 {x:Null} 清除了全局按钮背景色带来的影响。

Style类的属性

不知不觉中,我们已经学了样式的好几个属性,Setter 用于设置样式,TargetType用于设置样式应用的控件类型以及默认控件样式,BasedOn用于继承,而样式不止这几个属性,还有下面几个
在这里插入图片描述
由于触发器比较重要所以我们下一节用一节的篇幅学习Style的另一个属性,Trigger,触发器。

我们先看Style的另外一些知识。

关联事件处理程序

我们之前讲了Setter,还有一种EventSetter,用于绑定事件。事先说明,这种用法使用的很少,不感兴趣的可以直接跳过。

<Window.Resources>
    <Style TargetType="Button" x:Key="ClickBtnStyle">
        <EventSetter Event="Click" Handler="element_Click"/>
    </Style>
</Window.Resources>
<StackPanel>
    <Button x:Name="btn" Style="{StaticResource ClickBtnStyle}">Test Button</Button>
</StackPanel>

使用了ClickBtnStyle样式的按钮都会相应element_Click定义的点击事件。这种写法有一个限制就是必须写在窗体或者控件中,无法写在资源字典中(因为它必须连接事件处理程序,所以必须指明x:Class,但是资源字典没有这个属性)

我们在实际的开发中应该尽量不使用这种技术,这里仅做了解即可。

样式与共享依赖属性

我们在之前讲依赖项属性的时候提到过界面上Button和TextBlock虽然各自有各自的FontFamily属性,但是本质上是同一个依赖项属性的问题(因为使用了共享的依赖项属性),所以我们看下面的例子

<Style>
    <Setter Property="Button.FontFamily" Value="Times New Roman"/>
    <Setter Property="TextBlock.FontFamily" Value="Arial"/>
</Style>

在这个例子中我们期望把Button和TextBlock设置为不同的字体,但是事实上,两者的字体都被设置成了Arial,我们应当知道这个问题,在遇到问题的时候就可以节省很多解决问题的时间。

特别注意

  • 不仅仅是在样式中可以使用触发器,在FrameworkElement中也有Triggers集合,但是并不常用,因为这里面只能支持事件触发器
  • 如果我们使用Background进行测试,我们经常会发现一些属性的表现与我们设想的并不一致,这是因为按钮的行为不止受样式的影响,还受到模板的影响,两者相结合我们才能真正的完全控制一个控件。再之后我们学习模板的时候我们还会慢慢理解这种关系
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章