• 浅谈WPF之控件模板和数据模板


    WPF不仅支持传统的Windows Forms编程的用户界面和用户体验设计,同时还推出了以模板为核心的新一代设计理念。在WPF中,通过引入模板,将数据和算法的“内容”和“形式”进行解耦。模板主要分为两大类:数据模板【Data Template】和控件模板【Control Template】。

    图片

    基本上,ControlTemplate描述如何显示控件,而DataTemplate描述如何显示数据。

    控件模板 Control Template

    控件模板让我们可以定义控件的外观,改变控件的展现形式,通过Control Template实现。

    1. 编辑默认模板

    选中控件--右键--编辑模板--编辑副本,打开创建Style资源对话框,如下所示:

    图片

    创建Style资源,输入资源名称,定义位置,默认为此文档【Window】,然后点击【确定】,创建资源。如下所示:

    图片

    创建控件元素的默认资源,如下所示:

    1. <Window x:Class="WpfApp2.TwoWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:WpfApp2"
    7. mc:Ignorable="d"
    8. Title="TwoWindow" Height="350" Width="800">
    9. <Window.Resources>
    10. <Style x:Key="FocusVisual">
    11. <Setter Property="Control.Template">
    12. <Setter.Value>
    13. <ControlTemplate>
    14. <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
    15. ControlTemplate>
    16. Setter.Value>
    17. Setter>
    18. Style>
    19. <SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
    20. <SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
    21. <SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
    22. <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
    23. <SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
    24. <SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
    25. <SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
    26. <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
    27. <SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
    28. <Style x:Key="OneButtonStyle" TargetType="{x:Type Button}">
    29. <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
    30. <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
    31. <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
    32. <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    33. <Setter Property="BorderThickness" Value="1"/>
    34. <Setter Property="HorizontalContentAlignment" Value="Center"/>
    35. <Setter Property="VerticalContentAlignment" Value="Center"/>
    36. <Setter Property="Padding" Value="1"/>
    37. <Setter Property="Template">
    38. <Setter.Value>
    39. <ControlTemplate TargetType="{x:Type Button}">
    40. <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
    41. <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
    42. Border>
    43. <ControlTemplate.Triggers>
    44. <Trigger Property="IsDefaulted" Value="true">
    45. <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
    46. Trigger>
    47. <Trigger Property="IsMouseOver" Value="true">
    48. <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
    49. <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
    50. Trigger>
    51. <Trigger Property="IsPressed" Value="true">
    52. <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
    53. <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
    54. Trigger>
    55. <Trigger Property="IsEnabled" Value="false">
    56. <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
    57. <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
    58. <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
    59. Trigger>
    60. ControlTemplate.Triggers>
    61. ControlTemplate>
    62. Setter.Value>
    63. Setter>
    64. Style>
    65. Window.Resources>
    66. <Grid>
    67. <Button x:Name="one" Content="Hello wpf" Margin="5" Width="100" Height="30" Style="{DynamicResource OneButtonStyle}">Button>
    68. Grid>
    69. Window>

    编辑默认模板,也可以通过【文档大纲】右键--编辑模板--编辑副本,然后打开创建资源对话框,进行操作,如下所示:

    图片

    2. 修改默认样式

    通过默认创建的控件模板Style,可以修改和重定义控件的显示内容,如:设置按钮显示圆角,和鼠标放上去为红色。

     

    图片

    要实现以上功能,只需要修改两个地方即可,如下所示:

    图片

    3. 自定义控件模板

    通过自定义模板,同样能达到修改控件样式的效果。

    控件模板也是资源的一种,每一个控件模板都有一个唯一的key,在控件上通过Template进行绑定,如下所示:

    1. <Window x:Class="WpfApp2.ThreeWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:WpfApp2"
    7. mc:Ignorable="d"
    8. Title="自定义控件模板示例" Height="150" Width="300">
    9. <Window.Resources>
    10. <ControlTemplate x:Key="oneStyle" TargetType="Button">
    11. <Border Background="LightBlue" CornerRadius="5" x:Name="border">
    12. <StackPanel Orientation="Horizontal" HorizontalAlignment="{TemplateBinding HorizontalAlignment}">
    13. <TextBlock VerticalAlignment="{TemplateBinding VerticalAlignment}">》》TextBlock>
    14. <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">ContentPresenter>
    15. StackPanel>
    16. Border>
    17. <ControlTemplate.Triggers>
    18. <Trigger Property="IsMouseOver" Value="true">
    19. <Setter Property="Background" TargetName="border" Value="Red"/>
    20. <Setter Property="BorderBrush" TargetName="border" Value="Blue"/>
    21. Trigger>
    22. ControlTemplate.Triggers>
    23. ControlTemplate>
    24. Window.Resources>
    25. <Grid>
    26. <Button x:Name="one" Content="Hello wpf" Margin="5" Width="100" Height="30" VerticalAlignment="Center" HorizontalAlignment="Center" Template="{StaticResource oneStyle}">Button>
    27. Grid>
    28. Window>

    自定义控件模板,示例如下:

    图片

    数据模板 DataTemplate

    控件模板决定了数据的展示形式和用户体检,在软件UI设计中非常重要。同样数据的展示形式越来越多样化,正所谓:横看成岭侧成峰,远近高低各不同。同样的数据内容,在DataGrid中的展示是文本的列表形式,在ComboBox中是下拉框的形式。给数据披上外衣,将数据和形式解耦,是一种新的发展趋势。

    1. DataGrid

    1. 数据模板

    DataGrid是可以自定义网格数据显示的控件,通过自定义显示的列模板,可以实现各式各样的展现方式。列定义如下:

    1. DataGrid的列定义,通过Binding="{Binding Name}"的方式绑定属性,通过ElementStyle="{StaticResource one_center}"的方式绑定样式。

    2. DataGrid预制了几种列展示数据的方式,如:DataGridTextColumn【文本】,DataGridCheckBoxColumn【复选框】,DataGridComboBoxColumn【下拉框】,DataGridHyperlinkColumn【链接】等,如果使用数据模板,则采用DataGridTemplateColumn进行定义。

    UI示例如下所示:

    1. <Window x:Class="WpfApp2.A1Window"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:WpfApp2"
    7. mc:Ignorable="d"
    8. Title="数据模板示例" Height="450" Width="650">
    9. <Window.Resources>
    10. <Style x:Key="one_center" TargetType="TextBlock">
    11. <Setter Property="VerticalAlignment" Value="Center">Setter>
    12. <Setter Property="HorizontalAlignment" Value="Center">Setter>
    13. Style>
    14. <Style x:Key="one_header" TargetType="DataGridColumnHeader">
    15. <Setter Property="VerticalAlignment" Value="Center">Setter>
    16. <Setter Property="HorizontalAlignment" Value="Center">Setter>
    17. <Setter Property="HorizontalContentAlignment" Value="Center">Setter>
    18. <Setter Property="BorderThickness" Value="0">Setter>
    19. Style>
    20. Window.Resources>
    21. <Grid>
    22. <DataGrid x:Name="one" Margin="10" AutoGenerateColumns="False" CanUserAddRows="False" CanUserSortColumns="False" BorderThickness="0" >
    23. <DataGrid.Columns>
    24. <DataGridTextColumn Header="姓名" Binding="{Binding Name}" Width="*" ElementStyle="{StaticResource one_center}" HeaderStyle="{StaticResource one_header}" />
    25. <DataGridTextColumn Header="年龄" Binding="{Binding Age}" Width="*" ElementStyle="{StaticResource one_center}" HeaderStyle="{StaticResource one_header}"/>
    26. <DataGridTextColumn Header="性别" Binding="{Binding Sex}" Width="*" ElementStyle="{StaticResource one_center}" HeaderStyle="{StaticResource one_header}"/>
    27. <DataGridTextColumn Header="班级" Binding="{Binding Classes}" Width="*" ElementStyle="{StaticResource one_center}" HeaderStyle="{StaticResource one_header}"/>
    28. <DataGridTemplateColumn Header="操作" Width="*" HeaderStyle="{StaticResource one_header}">
    29. <DataGridTemplateColumn.CellTemplate>
    30. <DataTemplate>
    31. <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
    32. <Button x:Name="edit" Content="编辑" Width="60" Margin="3" Height="25">Button>
    33. <Button x:Name="delete" Content="删除" Width="60" Margin="3" Height="25">Button>
    34. StackPanel>
    35. DataTemplate>
    36. DataGridTemplateColumn.CellTemplate>
    37. DataGridTemplateColumn>
    38. DataGrid.Columns>
    39. DataGrid>
    40. Grid>
    41. Window>

    2.后台数据绑定

    后台数据绑定通过ItemsSource进行赋值,绑定的数据的属性名,要和DataGrid的列绑定数据的名称保持一致,如下所示:

    1. namespace WpfApp2
    2. {
    3. ///
    4. /// A1Window.xaml 的交互逻辑
    5. ///
    6. public partial class A1Window : Window
    7. {
    8. public A1Window()
    9. {
    10. InitializeComponent();
    11. List lst = new List();
    12. lst.Add(new Student() { Name = "张三", Age = 22, Sex = "男", Classes = "一班" });
    13. lst.Add(new Student() { Name = "李四", Age = 21, Sex = "男", Classes = "二班" });
    14. lst.Add(new Student() { Name = "王五", Age = 20, Sex = "女", Classes = "一班" });
    15. lst.Add(new Student() { Name = "刘大", Age = 19, Sex = "男", Classes = "三班" });
    16. lst.Add(new Student() { Name = "麻子", Age = 18, Sex = "男", Classes = "四班" });
    17. one.ItemsSource = lst;
    18. }
    19. }
    20. public class Student
    21. {
    22. public string Name { get; set; }
    23. public int Age { get; set; }
    24. public string Sex { get; set; }
    25. public string Classes { get; set; }
    26. }
    27. }

    DataGrid示例,如下所示:

    图片

    2. ListBox和ComboBox

    1. 数据模板

    ListBox,ComboBox,均是包含可选择的项的列表,只是ListBox不需要下拉显示,ComboBox需要下拉显示。通过定义数据模板,可以丰富数据的展示形式。

    通过ItemTemplate="{StaticResource item_template}"的形式,进行数据模板的绑定。如下所示:

    1. <Window x:Class="WpfApp2.A2Window"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:WpfApp2"
    7. mc:Ignorable="d"
    8. Title="数据模板示例" Height="450" Width="800">
    9. <Window.Resources>
    10. <DataTemplate x:Key="item_template">
    11. <StackPanel Orientation="Horizontal" Margin="5 ,0">
    12. <Border Width="10" Height="10" Background="{Binding Code}">Border>
    13. <TextBlock Text="{Binding Code}" Margin="5,0" >TextBlock>
    14. StackPanel>
    15. DataTemplate>
    16. Window.Resources>
    17. <Grid>
    18. <StackPanel Margin="3" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
    19. <ComboBox x:Name="one" Height="25" Width="120" Margin="5" ItemTemplate="{StaticResource item_template}">ComboBox>
    20. <ListBox x:Name="two" Width="120" Margin="5" ItemTemplate="{StaticResource item_template}">ListBox>
    21. StackPanel>
    22. Grid>
    23. Window>

    2.后台数据绑定

    与DataGrid一样,后台通过ItemsSource进行数据的绑定。如下所示:

    1. namespace WpfApp2
    2. {
    3. ///
    4. /// A2Window.xaml 的交互逻辑
    5. ///
    6. public partial class A2Window : Window
    7. {
    8. public A2Window()
    9. {
    10. InitializeComponent();
    11. List lst = new List();
    12. lst.Add(new Color() { Code = "#FE8C00" });
    13. lst.Add(new Color() { Code = "#1F7F50" });
    14. lst.Add(new Color() { Code = "#AA8C00" });
    15. lst.Add(new Color() { Code = "#FEAA00" });
    16. lst.Add(new Color() { Code = "#008CAA" });
    17. lst.Add(new Color() { Code = "#FEBB00" });
    18. one.ItemsSource = lst;
    19. two.ItemsSource = lst;
    20. }
    21. }
    22. public class Color
    23. {
    24. public string Code { get; set; }
    25. }
    26. }

    示例截图,如下所示:

    图片

    3. ItemsControl

    1. 数据模板

    ItemsControl,主要用于展示集合数据的项,也是列表控件的一种。ItemsControl 需要设置两个内容:

    • ItemsControl.ItemsPanel,做为数据展示的容器。

    • ItemsControl.ItemTemplate,用于单个数据的展示形式。

    具体如下所示:

    1. <Window x:Class="WpfApp2.A3Window"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:WpfApp2"
    7. mc:Ignorable="d"
    8. Title="A3Window" Height="450" Width="800">
    9. <Grid>
    10. <ItemsControl x:Name="one">
    11. <ItemsControl.ItemsPanel>
    12. <ItemsPanelTemplate>
    13. <WrapPanel>WrapPanel>
    14. ItemsPanelTemplate>
    15. ItemsControl.ItemsPanel>
    16. <ItemsControl.ItemTemplate>
    17. <DataTemplate>
    18. <Button Width="50" Height="50" Margin="5" Content="{Binding Code}">Button>
    19. DataTemplate>
    20. ItemsControl.ItemTemplate>
    21. ItemsControl>
    22. Grid>
    23. Window>

     

    2.后台数据绑定

    与DataGrid一样,后台通过ItemsSource进行数据的绑定。如下所示:

    1. namespace WpfApp2
    2. {
    3. ///
    4. /// A3Window.xaml 的交互逻辑
    5. ///
    6. public partial class A3Window : Window
    7. {
    8. public A3Window()
    9. {
    10. InitializeComponent();
    11. List lst = new List();
    12. lst.Add(new Test() { Code = "1" });
    13. lst.Add(new Test() { Code = "2" });
    14. lst.Add(new Test() { Code = "3" });
    15. lst.Add(new Test() { Code = "4" });
    16. lst.Add(new Test() { Code = "5" });
    17. lst.Add(new Test() { Code = "6" });
    18. one.ItemsSource = lst;
    19. }
    20. }
    21. public class Test
    22. {
    23. public string Code { get; set; }
    24. }
    25. }

    示例截图

    图片

    控件模板和数据模板的应用场景还有很多,本文旨在抛砖引玉,一起学习,共同进步。

  • 相关阅读:
    面向专业开发者的Python IDE——PyCharm,各个版本如何抉择?
    汽车ECU的虚拟化技术初探(三)--U2A虚拟化辅助功能分析1
    低代码开发在人工智能时代的多重前景
    语法基础(数组)
    深度学习推理框架汇总
    网站安全方案
    WebDAV之葫芦儿·派盘+简悦
    HNU计网实验:实验一 应用协议与数据包分析实验(使用Wireshark)
    ceph 笔记
    dockerfile用ENTRYPOINT好还是用CMD好
  • 原文地址:https://blog.csdn.net/fengershishe/article/details/134485010