控件模板

简介: 原文:控件模板1、理解逻辑树与可视化树。 添加的元素分类称之为逻辑树,可视化树是逻辑树的扩展版本,目的用于将元素分成更小的部分。WPF提供了用于浏览逻辑树和可视化树的两个类:System.Windows.LogicalTreeHelper和System.Windows.Media.VisualTreeHelper。
原文: 控件模板

1、理解逻辑树与可视化树。

添加的元素分类称之为逻辑树,可视化树是逻辑树的扩展版本,目的用于将元素分成更小的部分。WPF提供了用于浏览逻辑树和可视化树的两个类:System.Windows.LogicalTreeHelper和System.Windows.Media.VisualTreeHelper。VisualTreeHelper类还提供了一种研究应用程序中可视化树的有趣的方法,使用GetChild()方法,可以遍历任意串口的可视化树。

2、可视化树有两项非常重要的工作。

2.1)、可使用样式改变可视化树的元素。可使用Style.TargetType(很重要,假设不指定类型为Button,那么Button元素应用此模板不会显示内容)属性指定修改的特定元素,甚至当控件属性发生变化时,可使用触    发器自动完成更新。

2.2)、可为控件创建新模板。

3、分析可视化树。

先分析一下MainWinow窗口中的元素的逻辑树。 

<Window x:Class="可视化树.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">
    <StackPanel Margin="5">
        <Button Name="btn1" Padding="5" Margin="5" Click="cmd_Click">First Button</Button>
        <Button Name="btn2" Padding="5" Margin="5" Click="cmd_Click">Second Button</Button>
    </StackPanel>
</Window>

逻辑树:

可视化树:

新建一个名叫VisualTreeDisplay的Windows窗口,在窗口后台写代码。

VisualTreeDisplay窗口的xaml代码:

<Window x:Class="可视化树.VisualTreeDisplay"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="VisualTreeDisplay" Height="300" Width="300"> 
  <TreeView Name="treeElements"></TreeView> </Window>

VisualTreeDisplay窗口的后台代码:

public partial class VisualTreeDisplay : Window
{
    public VisualTreeDisplay()
    {
        InitializeComponent();
    }
    public void ShowVisualTree(DependencyObject element)
    {
        //先清除集合中的项。
        treeElements.Items.Clear();
        ProcessElement(element, null);
    }
    private void ProcessElement(DependencyObject element, TreeViewItem previousItem)
    {
        //创建视图树。
        TreeViewItem item = new TreeViewItem();
        //获取依赖元素标题。
        item.Header = element.GetType().Name;
        //打开折叠。
        item.IsExpanded = true;
        if (previousItem == null)
        {
            treeElements.Items.Add(item);
        }
        else
        {
            previousItem.Items.Add(item); 
        }
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
        {
            ProcessElement(VisualTreeHelper.GetChild(element, i), item);
        }
    }
}

在MainWindow中xaml代码:

<Window x:Class="可视化树.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">
    <StackPanel Margin="5">
        <Button Padding="5" Margin="5" Click="cmd_Click">First Button</Button>
        <Button Padding="5" Margin="5" Click="cmd_Click">Second Button</Button>
    </StackPanel>
</Window>

MainWindow后台代码: 

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void cmd_Click(object sender, RoutedEventArgs e)
    {
        //查看窗口的可视化状态:
        //VisualTreeDisplay vtd = new VisualTreeDisplay();
        //vtd.ShowVisualTree((this));
        //vtd.Show();
        
        //查看Button的可视化状态。
        VisualTreeDisplay vtd = new VisualTreeDisplay();
        vtd.ShowVisualTree((FrameworkElement)sender);
        vtd.Show();
    }
}

查看窗口的可视化状态(参数传的this),会显示出可视化逻辑状态窗口:

查看button的可视化逻辑窗口(里面有Border元素(用于修饰)和ContentPresenter元素(显示内容)):

在<StackPanel> 元素中再添加一个Image元素,命名为img1,接下来看看图片的可视化状态,说明(就显示个Image,说明没有可视化逻辑显示,不能应用模板):

private void img1_MouseDown(object sender, MouseButtonEventArgs e)
{            
    VisualTreeDisplay vtd = new VisualTreeDisplay();
    vtd.ShowVisualTree((FrameworkElement)sender);
    vtd.Show();
}

  

在上面的Window窗口中,可视化树包含了一个Border元素,这个Border元素又包含了一个AdornerSecorator元素(用于修饰),AdornerDecorator元素内是一个ContentPresenter元素(该元素承载了窗口内容),窗口内包含了一的StackPanel面板具有两个Button控件,每个Button控件包含了一个ButtonChrome元素(该元素绘制按钮的标准可视化外观)和一个ContentPresenter元素(该元素包含了元素的内容),每个按钮额ContentPresenter元素是一个TextBlock元素,TextBlock元素封装了在窗口中可见的文本。

4、理解模板

模板主要用于修改元素外观,但不能修改其行为。模板一般分为三种模板,分别是:控件模板(ControlTemplate)、数据模板(DataTemplate)和面板模板(ItemPanelTemplate),这些模板都继承自FrameworkTemplate基类。控件模板提供了在可视化树种看到的扩展内容,ButtonChorme类定义按钮的标准可视化外观,而ContentPresenter类存储了提供的所有内容。其中,ButtonChorme类继承自Decorator类(与Border类非常类似),这意味着这些类是为了在其他元素周围添加图形装饰而设计的。

5、创建简单控件模板。

为Button设置模板。

xaml代码:

<Window.Resources>
    <!--在资源中定义一个名叫button_template的模板-->
    <ControlTemplate x:Key="button_template" TargetType="{x:Type Button}>
        <!--添加Border元素,为其设置属性-->
        <Border BorderBrush="Orange" Background="LightCyan" TextBlock.Foreground="Black" BorderThickness="2" CornerRadius="5">
            <ContentPresenter RecognizesAccessKey='True' HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
        </Border>
    </ControlTemplate>
</Window.Resources>
    
<StackPanel>
    <!--为第一个Button元素设置模板。-->
    <Button Template="{StaticResource button_template}" Padding="5" Margin="5" Height="50">我是Button1</Button>
    <Button Padding="5" Margin="5" Height="50">我是Button2</Button>
</StackPanel>

效果图:

在上面的控件模板中,设置了TargetType属性,以明确指示该模板是为按钮设计的,与样式类似,这总是一个可以遵循的好约定,在内容控件(如Button)中也需要使用该约定。否则ContentPresenter元素就不能工作。从技术角度看,ContentPresenter之所以能工作,是因为它有一个模板绑定,用于将ContentPresenter.Content属性设置为Button.Content属性,然而该绑定是隐式的。

6、模板绑定。

<StackPanel>
    <!--为第一个Button元素设置模板。-->
    <Button Template="{StaticResource button_template}" Padding="5" Margin="10">我是Button1</Button>
    <Button Padding="5" Margin="5" Height="50">我是Button2</Button>
</StackPanel>

在该例中存在一个问题,现在为按钮添加的Margin属性指定为10,并将padding属性的值设置为5,Stackpanel控件关注的是按钮的Margin属性,却忽略了Padding属性,使按钮的内容和侧边挤压在一起,此处额问题是Padding属性不起作用,除非在模板中特别注意它,幸运的是WPF专门针对该目的设计了一个工具,模板绑定。通过使用模板绑定,模板可从应用模板的控件中提取一个值,就是为ContentPresenter元素中的Margin属性通过模板绑定到Paddding属性中。

<!--通过模板绑定到Padding属性上-->
<ContentPresenter Margin="{TemplateBinding Padding}" RecognizesAccessKey='True' HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
    
<StackPanel>
    <!--为Button元素设置模板。这样Padding属性就其作用了(如果为button设置了Height属性,将看不到效果,切记!)-->
    <Button Template="{StaticResource button_template}" Padding="20" Margin="10" >我是Button1</Button>
</StackPanel>

7、改变属性的触发器。

根据之前的为Button设置简单模板绑定,虽然可以改变元素的外观,但把鼠标放到元素上,或者点击图片时没有什么反应,这个时候使用属性触发器的IsMouseOver和IsPressed属性来解决这个问题。其中,IsMouseOver是鼠标滑到元素上的效果,IsPressed是点击图片的效果。设置效果的时候,可通过TargetName指定要修改的具体元素的属性。

<Window.Resources>
    <!--在资源中定义一个名叫button_template的模板-->
    <ControlTemplate x:Key="button_template" TargetType="{x:Type Button}">
        <!--添加Border元素,为其设置属性-->
        <Border Name="Border" BorderBrush="Orange" Background="LightCyan" TextBlock.Foreground="Black" BorderThickness="2" CornerRadius="5">
            <ContentPresenter Margin="{TemplateBinding Padding}" RecognizesAccessKey='True' HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
        </Border>
            
        <!--设置属性触发器-->
        <ControlTemplate.Triggers>
            <!--设置一个鼠标移动到元素上的效果(用IsMouseOver属性)-->
            <Trigger Property="IsMouseOver" Value="true">
                <Setter TargetName="Border" Property="Background" Value="DarkRed"></Setter>
                <Setter TargetName="Border" Property="BorderBrush" Value="Red"></Setter>
            </Trigger>
            <!--设置一个点击元素的效果(用IsPressed属性)-->
            <Trigger Property="IsPressed" Value="True">
                <Setter TargetName="Border" Property="Background" Value="Yellow"></Setter>
            </Trigger>                
        </ControlTemplate.Triggers>            
    </ControlTemplate>    
</Window.Resources>
    
<StackPanel>
    <!--为第一个Button元素设置模板。-->
    <Button Template="{StaticResource button_template}" Padding="20" Margin="10" >我是Button1</Button>
    <Button Padding="5" Margin="5" Height="50">我是Button2</Button>
</StackPanel>

8、焦点指示器。

 在以上案例中,如果存在多个按钮,如果点击了其中的一个按钮,不能明确地看出此按钮是否获取了焦点,但是可以很容易地添加另一个元素以显示是否具有焦点,并且可以简单地使用触发器根据Button.IsKeyBoardFocused属性隐藏显示该属性。

实现思路是:在Border元素中添加一个Grid元素,在Grid元素中添加一个Rectangle元素(默认是隐藏),然后再添加一个Contentpresenter元素。当点击图片的时候,触发Button元素的IsKeyboardFocused属性,然后将Rectangle显示出来。

<Window.Resources>
    <!--在资源中定义一个名叫button_template的模板-->
    <ControlTemplate x:Key="button_template" TargetType="{x:Type Button}">
        <Border Name="Border" BorderBrush="Orange" Background="LightCyan" TextBlock.Foreground="Black" BorderThickness="2" CornerRadius="5">
            <!--添加Border元素,为其设置属性-->
            <Grid>
                <!--添加矩形元素,将矩形设置成点划线,默认是隐藏-->
                <Rectangle Name="FocusRectangle" Visibility="Hidden" Stroke="Black" StrokeThickness="1" StrokeDashArray="1,2" SnapsToDevicePixels="True"></Rectangle>
                <!--为Grid中添加ContentPresenter元素-->
                <ContentPresenter Margin="{TemplateBinding Padding}" RecognizesAccessKey='True' HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
            </Grid>
        </Border>
            
        <!--设置属性触发器-->
        <ControlTemplate.Triggers>
            <!--设置一个鼠标移动到元素上的效果(用IsMouseOver属性)-->
            <Trigger Property="IsMouseOver" Value="true">
                <Setter TargetName="Border" Property="Background" Value="DarkRed"></Setter>
                <Setter TargetName="Border" Property="BorderBrush" Value="Red"></Setter>
            </Trigger>
            <!--设置一个点击元素的效果(用IsPressed属性)-->
            <Trigger Property="IsPressed" Value="True">
                <Setter TargetName="Border" Property="Background" Value="Yellow"></Setter>
            </Trigger> 
            <!--设置IsKeyboardFocused属性,将举行显示出来。-->
            <Trigger Property="IsKeyboardFocused" Value="True">
                <Setter TargetName="FocusRectangle" Property="Visibility" Value="Visible"></Setter>
            </Trigger>
        </ControlTemplate.Triggers>            
    </ControlTemplate>    
</Window.Resources>
    
<StackPanel>
    <!--为第一个Button元素设置模板。-->
    <Button Template="{StaticResource button_template}" Padding="20" Margin="10" >我是Button1</Button>
     <Button Template="{StaticResource button_template}" Padding="20" Margin="10" >我是Button2</Button>
    <Button Padding="5" Margin="5" Height="50">我是Button2</Button>
</StackPanel>

 效果图:当点击了第二个图片时,出现虚线。

9、润色按钮。

就是当按钮的IsEnabled=false的时候,设置背景色。这个时候需要设置IsEnabled属性触发器了。

<ControlTemplate.Triggers>
    <Trigger Property="IsEnabled" Value="False">
        <Setter TargetName="Border" Property="TextBlock.Foreground" Value="gray"></Setter>
        <Setter TargetName="Border" Property="Background" Value="MistyRose"></Setter>
    </Trigger>
</ControlTemplate.Triggers>

<Button Template="{StaticResource button_template}" IsEnabled="False" Padding="5" Margin="10" Height="50">我是Button3</Button>

 10、模板与样式。

模板和样式有类似之处,样式和模板都可以改变元素的外观。然而,样式被限制在一个小得多的范围之内。一般情况下,模板用于更改元素的外观,样式用于更改元素属性。

11、使用事件触发器(事件触发器一般用于动画)。

通过EventTrigger设置事件触发器,通过RoutedEvent指定事件。一般事件处理器用于处理动画。 

<Window.Resources>
    <!--定义一个控件模板-->
    <ControlTemplate x:Key="button_template" TargetType="{x:Type Button}">
        <!--添加Border元素-->
        <Border Name="Border" CornerRadius="5" BorderBrush="Orange" BorderThickness="3" Background="Azure">
            <!--添加Grid元素-->
            <Grid>
                <Rectangle SnapsToDevicePixels="True" Visibility="Hidden" StrokeDashArray="1,2" StrokeThickness="1"></Rectangle>
                <ContentPresenter Margin="{TemplateBinding Padding}" HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
            </Grid>
        </Border>
            
        <!--定义触发器-->
        <ControlTemplate.Triggers>
            <!--定义一个事件触发器(鼠标移动到元素上),改变Border元素的背景色-->
            <EventTrigger RoutedEvent="MouseEnter">
                <BeginStoryboard>
                    <Storyboard Storyboard.TargetName="Border" Storyboard.TargetProperty="Background.Color">
                        <ColorAnimation Duration="0:0:0:1" To="Blue">
                        </ColorAnimation>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
            <!--定义一个事件触发器(鼠标离开元素时发生),将Border元素的背景色改变成原来的背景色-->
            <EventTrigger RoutedEvent="MouseLeave">
                <BeginStoryboard>
                    <Storyboard Storyboard.TargetName="Border" Storyboard.TargetProperty="Background.Color">
                        <ColorAnimation Duration="0:0:0:0" To="Azure">
                        </ColorAnimation>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </ControlTemplate.Triggers>            
    </ControlTemplate>
</Window.Resources>
    
<StackPanel>
    <!--为图片应用模板-->
    <Button Template="{StaticResource button_template}" Padding="30" Margin="10" Width="150">我是Button1</Button>
    <Button Template="{StaticResource button_template}" Padding="30" Margin="10" Width="150">我是Button2</Button>
    <Button Template="{StaticResource button_template}" Padding="30" Margin="10" Width="150">我是Button3</Button>
</StackPanel>

 12、组织模板资源(将模板定义在资源字典中)。

当使用控件模板时,需要决定如何更广泛地共享模板,以及是否希望自动地或明确地应用模板,但是要思考一个问题,将他们限定在特定的窗口中吗?大多数情况下,控件模板应用于多个窗口,甚至可能应用于整个应用程序中,为避免多次定义模板,基本上都是定义在资源字典中,然后将他们合并到Application.Resource中,每个控件模板创建单独的资源字典,而不要把所有的模板都定义在同一个资源字典中。

添加名叫ButtonDictionary.xaml的资源字典: 

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <!--定义一个名叫HighlightBackground的画刷,用于设置鼠标移动到元素上触发的的IsMouseOver属性,更改Border背景色-->
    <RadialGradientBrush x:Key="HighlightBackground" RadiusX="1" RadiusY="5" GradientOrigin="0.5,0.3">
        <GradientStop Offset="0" Color="White"></GradientStop>
        <GradientStop Offset=".4" Color="Blue"></GradientStop>
    </RadialGradientBrush>
<!--定义一个名叫HighlightBackground的画刷,用于设置鼠标点击button时,触发的IsPressed属性,更改Border背景色。--> <RadialGradientBrush x:Key="PressedBackground" RadiusX="1" RadiusY="5" GradientOrigin="0.5,0.3"> <GradientStop Offset="0" Color="White"></GradientStop> <GradientStop Offset="1" Color="Blue"></GradientStop> </RadialGradientBrush> <!--定义一个画刷,目的用于设置Button按钮的背景色--> <SolidColorBrush x:Key="DefaultBackground" Color="Blue"></SolidColorBrush> <!--定义一个画刷,用于设置禁用按钮的背景色--> <SolidColorBrush x:Key="DisabledBackground" Color="Gray"></SolidColorBrush> <!--定义一个画刷,用于设置模板中的Border元素的颜色。--> <RadialGradientBrush x:Key="Border" RadiusX="1" RadiusY="5" GradientOrigin="0.5,0.3"> <GradientStop Offset="0" Color="White"></GradientStop> <GradientStop Offset="1" Color="Blue"></GradientStop> </RadialGradientBrush> <!--定义一个名叫ContentPresenter_Style的样式,用于更改模板中的样式,将字体颜色变成白色。--> <Style x:Key="ContentPresenter_Style"> <Setter Property="Control.Foreground" Value="White"></Setter> </Style> <!--定义个模板--> <ControlTemplate x:Key="GradientTemplate" TargetType="{x:Type Button}"> <Border Name="Border" BorderBrush="{StaticResource ResourceKey=Border}" BorderThickness="2" CornerRadius="2" Background="{StaticResource ResourceKey=DefaultBackground}"> <Grid> <Rectangle Name="FocusRectangle" Visibility="Hidden" Stroke="Black" StrokeThickness="1" StrokeDashArray="1,2" SnapsToDevicePixels="True"></Rectangle> <ContentPresenter Name="cp" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True"></ContentPresenter> </Grid> </Border> <!--定义模板触发器--> <ControlTemplate.Triggers> <!--定义属性触发器(鼠标移动到元素上)--> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="Border" Property="Background" Value="{StaticResource ResourceKey=HighlightBackground}"></Setter> <Setter TargetName="cp" Property="Style" Value="{StaticResource ResourceKey= ContentPresenter_Style}"></Setter> </Trigger> <!--定义属性触发器(点击元素时触发)--> <Trigger Property="IsPressed" Value="True"> <Setter TargetName="Border" Property="Background" Value="{StaticResource ResourceKey=PressedBackground}"></Setter> </Trigger> <!--定义属性触发器(获取焦点)--> <Trigger Property="IsKeyboardFocused" Value="True"> <Setter TargetName="FocusRectangle" Property="Visibility" Value="Visible"></Setter> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter TargetName="Border" Property="Background" Value="{StaticResource ResourceKey=DisabledBackground}"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </ResourceDictionary>

 将资源字典合并到App.xaml文件中的<Application.Resources>节点中。

<ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="ButtonDictionary.xaml"></ResourceDictionary>
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

在窗口中引用:

<StackPanel>
    <Button Template="{StaticResource GradientTemplate}" Padding="30" Margin="10" Width="150">我是Button1</Button>
    <Button Template="{StaticResource GradientTemplate}" Padding="30" Margin="10" Width="150">我是Button2</Button>
    <Button Template="{StaticResource GradientTemplate}" IsEnabled="False" Padding="30" Margin="10" Width="150">我是Button3</Button>
</StackPanel>

效果图:

 13、通过样式应用模板。

就是在ButtonDictionary.xaml文件中添加一个style样式,为样式设置模板属性,然后值指向定义的模板,然后在窗口中设置元素的style属性指向ButtonDictionary.xaml文件中定义的样式即可。

在ButtonDictionary.xaml文件中添加Style样式: 

<!--添加名叫Button_Style的样式,设置Template属性,值指向定义的模板-->
<Style x:Name="Button_Style" TargetType="{x:Type Button}">
    <Setter Property="Template" Value="{StaticResource ResourceKey=GradientTemplate}"></Setter>
</Style>

在窗口中引用样式: 

<StackPanel> 
    <!--在这个地方是为元素设置样式,而不是通过模板哦--->
    <Button Style="{StaticResource Button_Style}"  Padding="30" Margin="10" Width="150">我是Button1</Button>
    <Button Padding="30" Margin="10" Width="150">我是Button2</Button>
    <Button Style="{StaticResource Button_Style}" IsEnabled="False" Padding="30" Margin="10" Width="150">我是Button3</Button>    
</StackPanel>

效果图:

 

14、自动应用模板。

也是在ButtonDictionary.xaml中添加一个Style样式,然后为其设置TargetType属性,不要为其指定x:key特性即可。应用模板不可以自动应用到元素上了。 

<!--添加Style样式,设置模板属性,值等于上面定义的模板。不用为其指定x:key特性就会自动应用到Button元素上了-->
<Style TargetType="{x:Type Button}">
    <Setter Property="Control.Template" Value="{StaticResource GradientTemplate}"></Setter>
</Style>

窗口中不用引用,就会自动应用了:

<StackPanel>       
    <Button Padding="30" Margin="10" Width="150">我是Button1</Button>
    <Button Padding="30" Margin="10" Width="150">我是Button2</Button>
    <Button IsEnabled="False" Padding="30" Margin="10" Width="150">我是Button3</Button>        
</StackPanel>

效果图:

 15、皮肤。

在一些应用程序中,可能希望动态地改变模板,比如通常所说的皮肤。基本技巧是运行时加载新的资源字典,并使用新加载的资源字典替代当前的资源字典(不需要替换所有资源,只需要替换那些用于皮肤的资源)。主要用于检索ResourceDictionary对象,该对象经过编译并作为资源嵌入到应用程序中。

16、构建更复杂的模型。

嵌套的模板:

xaml代码:

<Window x:Class="嵌套的模型.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>
        <!--定义一个名叫HighlightBackground的画刷,用于设置鼠标移动到元素上触发的的IsMouseOver属性,更改Border背景色-->
        <RadialGradientBrush x:Key="HighlightBackground" RadiusX="1" RadiusY="5" GradientOrigin="0.5,0.3">
            <GradientStop Offset="0" Color="White"></GradientStop>
            <GradientStop Offset=".4" Color="Blue"></GradientStop>
        </RadialGradientBrush>

        <!--定义一个名叫HighlightBackground的画刷,用于设置鼠标点击button时,触发的IsPressed属性,更改Border背景色。-->
        <RadialGradientBrush x:Key="PressedBackground" RadiusX="1" RadiusY="5" GradientOrigin="0.5,0.3">
            <GradientStop Offset="0" Color="White"></GradientStop>
            <GradientStop Offset="1" Color="Blue"></GradientStop>
        </RadialGradientBrush>

        <!--定义一个画刷,目的用于设置Button按钮的背景色-->
        <SolidColorBrush x:Key="DefaultBackground" Color="Blue"></SolidColorBrush>
        <!--定义一个画刷,用于设置禁用按钮的背景色-->
        <SolidColorBrush x:Key="DisabledBackground" Color="Gray"></SolidColorBrush>

        <!--定义一个画刷,用于设置模板中的Border元素的颜色。-->
        <RadialGradientBrush x:Key="Border" RadiusX="1" RadiusY="5" GradientOrigin="0.5,0.3">
            <GradientStop Offset="0" Color="White"></GradientStop>
            <GradientStop Offset="1" Color="Blue"></GradientStop>
        </RadialGradientBrush>

        <!--定义一个名叫ContentPresenter_Style的样式,用于更改模板中的样式,将字体颜色变成白色。-->
        <Style x:Key="ContentPresenter_Style">
            <Setter Property="Control.Foreground" Value="White"></Setter>
        </Style>
    </Window.Resources>
    
    <StackPanel>
        <Button Content="Hello,World" Height="80" Margin="10">
            <Button.Style>
                <Style>
                    <Setter Property="Button.Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="Button">
                                <Border Name="Border" BorderBrush="{StaticResource ResourceKey=Border}" BorderThickness="2" CornerRadius="2" Background="{StaticResource ResourceKey=DefaultBackground}">
                                    <Grid>
                                        <Rectangle Name="FocusRectangle" Visibility="Hidden" Stroke="Black" StrokeThickness="1" StrokeDashArray="1,2" SnapsToDevicePixels="True"></Rectangle>
                                        <ContentPresenter Name="cp"  HorizontalAlignment="Center" VerticalAlignment="Center" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True"></ContentPresenter>
                                    </Grid>
                                </Border>

                                <ControlTemplate.Triggers>
                                    <!--定义属性触发器(鼠标移动到元素上)-->
                                    <Trigger Property="IsMouseOver" Value="True">
                                        <Setter TargetName="Border" Property="Background" Value="{StaticResource ResourceKey=HighlightBackground}"></Setter>
                                        <Setter TargetName="cp" Property="Style" Value="{StaticResource ResourceKey= ContentPresenter_Style}"></Setter>
                                    </Trigger>

                                    <!--定义属性触发器(点击元素时触发)-->
                                    <Trigger Property="IsPressed" Value="True">
                                        <Setter TargetName="Border" Property="Background" Value="{StaticResource ResourceKey=PressedBackground}"></Setter>
                                    </Trigger>

                                    <!--定义属性触发器(获取焦点)-->
                                    <Trigger Property="IsKeyboardFocused" Value="True">
                                        <Setter TargetName="FocusRectangle" Property="Visibility" Value="Visible"></Setter>
                                        <Setter TargetName="Border" Property="Background" Value="Yellow"></Setter>
                                    </Trigger>
<Trigger Property="IsEnabled" Value="false"> <Setter TargetName="Border" Property="Background" Value="{StaticResource ResourceKey=DisabledBackground}"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </Button.Style> </Button> </StackPanel> </Window>

效果图:

 

17、圆角图片。

xaml代码:

<Border BorderBrush="Red" BorderThickness="2" Margin="10" Width="202" Height="202" CornerRadius="5">
    <Grid Width="200" Height="200" Margin="-1,-1,0,0">
        <Border  Name="myBorder" CornerRadius="5" Background="White"/>
        <Image Source="1.jpg" Margin="1" Stretch="Fill">
            <Image.OpacityMask>
                <VisualBrush Visual="{Binding ElementName=myBorder}"/>
            </Image.OpacityMask>
        </Image>
    </Grid>
</Border>

效果图:

 

 End。

目录
相关文章
|
关系型数据库 MySQL C#
C# winform 一个窗体需要调用自定义用户控件的控件名称
给用户控件ucQRCode增加属性: //二维码图片 private PictureBox _pictureBoxFSHLQrCode; public PictureBox PictureBoxFSHLQrCode {   get { return _pictureBoxFSHLQrCode; }   set { this.pictureBoxFSHLQrCode = value; } } 在Form1窗体直接调用即可: ucQRCode uQRCode=new ucQRCode(); ucQRCode.PictureBoxFSHLQrCode.属性= 要复制或传给用户控件上的控件的值
71 0
|
算法 C# UED
浅谈WPF之控件模板和数据模板
WPF不仅支持传统的Windows Forms编程的用户界面和用户体验设计,同时还推出了以模板为核心的新一代设计理念。在WPF中,通过引入模板,将数据和算法的“内容”和“形式”进行解耦。模板主要分为两大类:数据模板【Data Template】和控件模板【Control Template】。
206 8
|
开发工具 C语言 索引
Qt编写自定义控件8-动画按钮组控件
一、前言 动画按钮组控件可以用来当做各种漂亮的导航条用,既可以设置成顶部底部+左侧右侧,还自带精美的滑动效果,还可以设置悬停滑动等各种颜色,原创作者雨田哥(QQ:3246214072),驰骋Qt控件界多年,雨田哥是我见过的在这块水平相当牛逼的,在我之上,想要什么效果都可以搞出来,大家也可以找他定制...
1316 0
|
Android开发
UWP 查找模板中的控件
原文:UWP 查找模板中的控件 这个标题我也不知道咋起,意思说一下你就明白。 1. 对官方控件的模板进行定制修改,以满足多样化需求,还有漂亮的UI 比如ListView,GridView等。 2.
808 0
下一篇
无影云桌面