微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

WPF样式的使用

1、样式的定义

样式的元素名称为Style,通过targettype来声明作用的目标的类型,通过Setter来声明作用目标的属性一个Style中可以添加多个Setter,在控件中使用Style的x:Key值来引用这个样式,下面实现对按钮的样式定义。

1.1 定义样式

<Window.Resources>
    <!--定义按钮公共样式-->
    <Style x:Key="gBut" targettype="{x:Type Button}">
        <!--手型-->
        <Setter Property="Cursor" Value="Hand"/>
        <!--宽度-->
        <Setter Property="Width" Value="150"/>
        <!--长度-->
        <Setter Property="Height" Value="80"/>
    </Style>
        
    <!--定义按钮样式1-->
    <Style x:Key="cBtn1" targettype="{x:Type Button}" BasedOn="{StaticResource gBut}">
        <!--背景色-->
        <Setter Property="Background" Value="Black"/>
        <!--字号-->
        <Setter Property="FontSize" Value="24"/>
        <!--字颜色-->
        <Setter Property="Foreground" Value="Blue"/>
        <!--字间距-->
        <Setter Property="Margin" Value="20"/>
    </Style>

    <!--定义按钮样式2-->
    <Style x:Key="cBtn2" targettype="{x:Type Button}" BasedOn="{StaticResource gBut}">
        <!--背景色-->
        <Setter Property="Background" Value="White"/>
        <!--字号-->
        <Setter Property="FontSize" Value="24"/>
        <!--字颜色-->
        <Setter Property="Foreground" Value="Red"/>
        <!--字间距-->
        <Setter Property="Margin" Value="10"/>
    </Style>
</Window.Resources>

BasedOn属性:通过设置BasedOn属性,可以继承某个样式。

1.2 引用样式

<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
    <!--应用样式1的按钮-->
    <Button Content="蓝色" Style="{StaticResource cBtn1}"/>
        
    <!--应用样式2的按钮-->
    <Button Content="白色" Style="{StaticResource cBtn2}"/>

    <!--应用样式3的按钮-->
    <Button Content="红色">
        <Button.Style>
            <!--定义按钮样式3-->
            <Style targettype="{x:Type Button}" BasedOn="{StaticResource gBut}">
                <!--背景色-->
                <Setter Property="Background" Value="Red"/>
                <!--字号-->
                <Setter Property="FontSize" Value="24"/>
                <!--字颜色-->
                <Setter Property="Foreground" Value="Red"/>
                <!--字间距-->
                <Setter Property="Margin" Value="20"/>
            </Style>
        </Button.Style>
    </Button>
</StackPanel>

2、样式的作用域

2.1 全局样式

全局样式:只要把样式元素写在App.xaml中即可。

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <!--全局应用程序资源-->
    <Application.Resources>
        <!--定义全局样式-->

    </Application.Resources>
</Application>

2.2 局部样式

<!--窗口资源-->
<Window.Resources>
    <!--定义局部样式-->
    
</Window.Resources>

2.3 内部样式

<Button Content="红色" Width="150" Height="80">
    <Button.Style>
        <!--定义内部-->
        <Style targettype="{x:Type Button}" BasedOn="{StaticResource gBut}">
            <!--背景色-->
            <Setter Property="Background" Value="Red"/>
            <!--字号-->
            <Setter Property="FontSize" Value="24"/>
        </Style>
    </Button.Style>
</Button>

以上的样式引用时的方法是一样的,都是使用Resources,内部样式的使用仅限于改控件本身,因为它没有被放到资源字典之中,xxx.Resources是支持向下继承的,并可以应用它在资源中的定义样式,例如:

<Grid>
    <!--定义Grid控件的资源-->
    <Grid.Resources>
        <!--定义按钮样式1-->
        <Style x:Key="grid_button" targettype="{x:Type Button}">
            <Setter Property="Width" Value="260"/>
            <Setter Property="Height" Value="160"/>
            <Setter Property="FontSize" Value="26"/>
            <Setter Property="Content" Value="应用父级样式"/>
        </Style>
    </Grid.Resources>
    <!--应用父级样式的按钮-->
    <Button Style="{StaticResource grid_button}"></Button>
</Grid>

运行结果所示,XAML代码中的按钮除了Style="{StaticResource grid_button}"之外并没有声明任何属性,按钮的尺寸和内容都是通过应用父级Grid资源样式来呈现的,所以只要父级的对象定义了资源,父级以下的元素均可以访问它的资源字典。


3、Style中的Trigger

Trigger,触发器,即当某些条件满足时会触发一个行为(比如某些值的变化或动画的发生等)。触发器比较像事件。事件一般是由用户操作触发的,而触发器除了有事件触发型的EventTrigger外还有数据变化触发型的Trigger/DataTrigger及多条件触发型MultiTrigger/multidatatrigger等。

3.1 基本Trigger

Trigger类是最基本的触发器。类似于Setter,Trigger也有Property和Value这两个属性,Property是Trigger关注的属性名称,Value是触发条件。Trigger类还有一个Setters属性,此属性值是一组Setter,一旦触发条件被满足,这组Setter的“属性—值”就会被应用,触发条件不再满足后,各属性值会被还原。

下面这个例子中包含一个针对CheckBox的Style,当CheckBox的IsChecked属性为true的时候前景色和字体会改变。XAML代码如下:

<Window.Resources>
    <Style targettype="CheckBox">
        <Style.Triggers>
            <Trigger Property="IsChecked" Value="true">
                <Setter Property="FontSize" Value="20"/>
                <Setter Property="Foreground" Value="Orange"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
    
<StackPanel>
    <CheckBox Content="悄悄的我走了" Margin="5"/>
    <CheckBox Content="正如我悄悄的来" Margin="5,0"/>
    <CheckBox Content="我挥一挥衣袖" Margin="5"/>
    <CheckBox Content="不带走一片云彩" Margin="5,0"/>
</StackPanel>

3.2 MultiTrigger

MultiTrigger是个容易让人误解的名字,会让人以为是多个Trigger集成在一起,实际上叫MultiConditionTrigger更合适,因为必须多个条件同时成立时才会触发。MultiTrigger比Trigger多了一个Conditions属性,需要同时成立的条件就储存在这个集合中。

让我们稍微改动一下上面的例子,要求同时满足CheckBox被选中且Content为“正如我悄悄的来”时才会被触发。XAML代码如下:

<Window.Resources>
    <Style targettype="CheckBox">
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsChecked" Value="true"/>
                    <Condition Property="Content" Value="正如我悄悄的来"/>
                </MultiTrigger.Conditions>
                <MultiTrigger.Setters>
                    <Setter Property="FontSize" Value="20"/>
                    <Setter Property="Foreground" Value="Orange"/>
                </MultiTrigger.Setters>
            </MultiTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
    
<StackPanel>
    <CheckBox Content="悄悄的我走了" Margin="5"/>
    <CheckBox Content="正如我悄悄的来" Margin="5,0"/>
</StackPanel>

3.3 由数据触发的DataTrigger

程序中经常会遇到基于数据执行某些判断情况,遇到这种情况时我们可以考虑使用DataTrigger。DataTrigger对象的Binding属性会把数据源不断送过来,一旦送了的值与Value属性一致,DataTrigger即被触发。

下面例子中,当TextBox的Text长度小于7个字符时其Border会保持红色。XAML代码如下:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="WPF样式的使用" Height="500" Width="800" WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <local:L2BConverter x:Key="cvtr" />
        <Style targettype="TextBox">
            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={x:Static RelativeSource.Self},Path=Text.Length,Converter={StaticResource cvtr}}" Value="false">
                    <Setter Property="BorderBrush" Value="Red"/>
                    <Setter Property="BorderThickness" Value="1"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    
    <StackPanel>
        <TextBox Margin="5"/>
        <TextBox Margin="5,0"/>
        <TextBox Margin="5"/>
    </StackPanel>
</Window>

这里用到了Converter,我们创建如下的Converter:

using System;
using System.Windows.Data;

namespace WpfApplication1
{
    public class L2BConverter : IValueConverter
    {
        public object Convert(object value,Type targettype,object parameter,System.Globalization.CultureInfo culture)
        {
            int textLength = (int)value;
            return textLength > 6 ? true : false;
        }

        public object ConvertBack(object value,System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
经Converter转换后,长度值会转换成bool类型值。DataTrigger的Value被设置为false,也就是说当TextBox的文本长度小于7时DataTrigger会使用自己的一组Setter把TextBox的边框设置为红色。

3.4 多条件触发的multidatatrigger

有时候我们会遇到要求多个数据条件同时满足时才能触发变化的需求,此时可以考虑使用multidatatrigger。比如有这样一个需求:用户界面使用ListBox显示了一列Student数据,当Student对象同时满足ID为2、Name为Tom的时候,条目就高亮显示,XAML代码如下:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="WPF样式的使用" Height="500" Width="800" WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <Style targettype="ListBoxItem">
            <!--使用Style设置DataTemplate-->
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding ID}" Width="60"/>
                            <TextBlock Text="{Binding Name}" Width="120"/>
                            <TextBlock Text="{Binding Age}" Width="60"/>
                        </StackPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
            <!--multidatatrigger-->
            <Style.Triggers>
                <multidatatrigger>
                    <multidatatrigger.Conditions>
                        <Condition Binding="{Binding Path=ID}" Value="2"/>
                        <Condition Binding="{Binding Path=Name}" Value="Tom"/>
                    </multidatatrigger.Conditions>
                    <multidatatrigger.Setters>
                        <Setter Property="Background" Value="Orange"/>
                    </multidatatrigger.Setters>
                </multidatatrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    
    <StackPanel>
        <ListBox x:Name="listBoxStudent" Margin="5"/>
    </StackPanel>
</Window>
后台代码

/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        List<Student> stuList = new List<Student>(){
            new Student(){ID="1",Name="Peter",Age=25},new Student(){ID="2",Name="Tom",Age=27},new Student(){ID="3",Name="Ben",Age=20}
        };

        this.listBoxStudent.ItemsSource = stuList;
    }

}

/// <summary>
/// 学生类
/// </summary>
public class Student{
    public string ID{get;set;}
    public string Name { get; set; }
    public int Age { get; set; }
}

3.5 由事件触发的EventTrigger

EventTrigger是触发器中最特殊的一个。首先,它不是由属性值或数据的变化来触发而是由事件来触发;其次,被触发后它并非应用一组Setter,而是执行一段动画。因此,UI层的动画效果往往与EventTrigger相关联。

在下面这个例子中创建了一个针对Button的Style,这个Style包含两个EventTrigger,一个由MouseEnter事件触发,另一个由MouseLeave事件触发。XAML代码如下:

<Window.Resources>
    <Style targettype="Button">
        <Style.Triggers>
            <!--鼠标进入-->
            <EventTrigger RoutedEvent="MouseEnter">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation To="150" Duration="0:0:0.2" Storyboard.TargetProperty="Width"/>
                        <DoubleAnimation To="150" Duration="0:0:0.2" Storyboard.TargetProperty="Height"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
            <!--鼠标离开-->
            <EventTrigger RoutedEvent="MouseLeave">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation  Duration="0:0:0.2" Storyboard.TargetProperty="Width"/>
                        <DoubleAnimation  Duration="0:0:0.2" Storyboard.TargetProperty="Height"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
    
<Canvas>
    <Button Width="40" Height="40" Content="OK"/>
</Canvas>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐