• WPF Template模版之DataTemplate与ControlTemplate【一】


     

    WPF Template模版之DataTemplate与ControlTemplate【一】

    标签: Wpf模版
     分类:
     

    目录(?)[+]

     

        WPF系统不但支持传统的Winfrom编程的用户界面和用户体验设计,更支持使用专门的设计工具Blend进行专业设计,同时还推出了以模板为核心的新一代设计理念。

    1. 模板的内涵

        作为表现形式,每个控件都是为了实现某种用户操作算法和直观显示某种数据而生,一个控件看上去是什么样子由它的“算法内容”和“数据内容"决定,这就是内容决定形式,这里,我们引入两个概念:

    控件的算法内容:控件能展示哪些数据、具有哪些方法、能响应哪些操作、能激发什么事件,简而言之就是控件的功能,它们是一组相关的算法逻辑。
    控件的数据内容:控件具体展示的数据是什么。


         以往的GUI开发技术(ASP.NET+Winform)中,控件内部逻辑和数据是固定的,程序员不能改变;对于控件的外观,程序员能做的改变也非常的有限,一般也就是设置控件的属性,想改变控件的内部结构是不可能的。如果想扩展一个控件的功能或者更改器外观让其更适应业务逻辑,哪怕只是一丁点的改变,也需要创建控件的子类或者创建用户控件。造成这个局面的根本原因是数据和算法的“形式”和“内容”耦合的太紧了。


        在WPF中,通过引入模板,微软将数据和算法的内容与形式解耦了。WPF中的Template分为两大类:
    ControlTemplate:是算法内容的表现形式,一个控件怎么组织其内部结构才能让它更符合业务逻辑、让用户操作起来更舒服就是由它来控制的。它决定了控件“长成什么样子”,并让程序员有机会在控件原有的内部逻辑基础上扩展自己的逻辑。
    DataTemplate:是数据内容的展示方式,一条数据显示成什么样子,是简单的文本还是直观的图形就由它来决定了。


    Template就是数据的外衣-----ControlTemplate是控件的外衣,DataTemplate是数据的外衣。

    2. 数据的外衣DataTemplate

        WPF不但支持UserControl还支持DataTemplate为数据形成视图。不要以为DataTemplate有多难!从UserControl升级到DataTemplate一般就是复制,粘贴一下再改几个字符的事儿。

    DataTemplate常用的地方有三处,分别是:
    ContentControl的ContentTemplate属性,相当于给ContentControl的内容穿衣服。
    ItemsControl的ItemTemplate,相当于给ItemControl的数据条目穿衣服。
    GridViewColumn的CellTempldate属性,相当于给GridViewColumn的数据条目穿衣服。

        事件驱动是控件和控件之间沟通或者说是形式和形式之间的沟通,数据驱动则是数据与控件之间的沟通,是内容决定形式。使用DataTemplate就可以方便的把事件驱动模式转换为数据驱动模式。

        让我们用一个例子体现DataTemplate的使用。例子实现的需求是这样的:有一列汽车数据,这列数据显示在ListBox里面,要求ListBox的条目显示汽车的厂商图标和简要参数,单击某个条目后在窗体的详细内容区显示汽车的图片和详细参数。厂商的Logo和汽车的照片都是要用到的,所以先在项目中建立资源管理目录并把图片添加进来。Logo文件名与厂商的名称一致,照片的名称则与车名一致。组织结构如图:

     

    创建Car数据类型:

    [csharp] view plain copy
     
     print?
    1. /// <summary>  
    2. /// Car数据类型 -- 必须定义成属性{ get; set; }  
    3. /// </summary>  
    4. public class Car  
    5. {  
    6.     public string Name { get; set; }  
    7.     public string ImagePath { get; set; }  
    8.     public string Automarker { get; set; }  
    9.     public string Year { get; set; }  
    10. }  

    汽车厂商和名称不能直接拿来作为图片路径,这时就要使用Converter:

    [csharp] view plain copy
     
     print?
    1. /// <summary>  
    2.     /// 路径转图片  
    3.     /// </summary>  
    4.     public class PathToImage:IValueConverter  
    5.     {  
    6.         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)  
    7.         {  
    8.             string url = (string)value;  
    9.             return(new BitmapImage(new Uri(url, UriKind.Relative)));  
    10.         }  
    11.   
    12.         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)  
    13.         {  
    14.             throw new NotImplementedException();  
    15.         }  
    16.     }  

    XAML中添加条目模版:

    [html] view plain copy
     
     print?
    1. <DataTemplate x:Key="_carListItemViewTemplate">  
    2.     <Grid Margin="2">  
    3.         <StackPanel Orientation="Horizontal">  
    4.             <Image Source="{Binding Path=Automarker, Converter={StaticResource _path2Image}}" Grid.RowSpan="3"  
    5.                    Width="64" Height="64"></Image>  
    6.             <StackPanel Margin="5,10">  
    7.                 <TextBlock Text="{Binding Name}" FontSize="16" FontWeight="Bold"></TextBlock>  
    8.                 <TextBlock Text="{Binding Year}" FontSize="14"></TextBlock>  
    9.             </StackPanel>  
    10.         </StackPanel>  
    11.     </Grid>  
    12. </DataTemplate>  
    XAML中添加显示详细信息的模版:
    [html] view plain copy
     
     print?
    1. <DataTemplate x:Key="_carDetailViewTemplate">  
    2.     <Border BorderBrush="Black" BorderThickness="1" CornerRadius="6">  
    3.         <StackPanel Margin="5">  
    4.             <Image Width="400" Height="250" Source="{Binding Path=ImagePath, Converter={StaticResource _path2Image}}"></Image>  
    5.             <StackPanel Orientation="Horizontal" Margin="5, 0">  
    6.                 <TextBlock Text="Name:" FontWeight="Bold" FontSize="20"></TextBlock>  
    7.                 <TextBlock Text="{Binding Path=Name}" FontSize="20" Margin="5, 0"></TextBlock>  
    8.             </StackPanel>  
    9.         </StackPanel>  
    10.     </Border>  
    11. </DataTemplate>  
    完整的XAML代码:
    [html] view plain copy
     
     print?
    1. <Window x:Class="WpfApplication11.wnd112"  
    2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    4.         xmlns:local="clr-namespace:WpfApplication11"  
    5.         Title="DataTemplate" Height="350" Width="623">  
    6.     <Window.Resources>  
    7.         <!--Convert-->  
    8.         <local:PathToImage x:Key="_path2Image"></local:PathToImage>  
    9.         <!--DataTemplate for Detail View -->  
    10.         <DataTemplate x:Key="_carDetailViewTemplate">  
    11.             <Border BorderBrush="Black" BorderThickness="1" CornerRadius="6">  
    12.                 <StackPanel Margin="5">  
    13.                     <Image Width="400" Height="250" Source="{Binding Path=ImagePath, Converter={StaticResource _path2Image}}"></Image>  
    14.                     <StackPanel Orientation="Horizontal" Margin="5, 0">  
    15.                         <TextBlock Text="Name:" FontWeight="Bold" FontSize="20"></TextBlock>  
    16.                         <TextBlock Text="{Binding Path=Name}" FontSize="20" Margin="5, 0"></TextBlock>  
    17.                     </StackPanel>  
    18.                 </StackPanel>  
    19.             </Border>  
    20.         </DataTemplate>  
    21.         <!--DataTemplate for Item View -->  
    22.         <DataTemplate x:Key="_carListItemViewTemplate">  
    23.             <Grid Margin="2">  
    24.                 <StackPanel Orientation="Horizontal">  
    25.                     <Image Source="{Binding Path=Automarker, Converter={StaticResource _path2Image}}" Grid.RowSpan="3"  
    26.                            Width="64" Height="64"></Image>  
    27.                     <StackPanel Margin="5,10">  
    28.                         <TextBlock Text="{Binding Name}" FontSize="16" FontWeight="Bold"></TextBlock>  
    29.                         <TextBlock Text="{Binding Year}" FontSize="14"></TextBlock>  
    30.                     </StackPanel>  
    31.                 </StackPanel>  
    32.             </Grid>  
    33.         </DataTemplate>  
    34.     </Window.Resources>      
    35.     <!---Window Content-->  
    36.     <StackPanel Orientation="Horizontal" Margin="5">  
    37.         <UserControl ContentTemplate="{StaticResource _carDetailViewTemplate}" Content="{Binding Path=SelectedItem, ElementName=_listBoxCars}"></UserControl>  
    38.         <ListBox x:Name="_listBoxCars" Width="180" Margin="5,0" ItemTemplate="{StaticResource _carListItemViewTemplate}"></ListBox>  
    39.     </StackPanel>  
    40. </Window>  

        代码对于初学者来说有点长但是结构非常简单。其中最重要的有两句:
    ContentTemplate="{StaticResource _carDatialViewTemplate}",相当于给一个普通的UserControl穿上了一件外衣、让Car数据以图文并茂的方式展现出来。这件外衣就是x:Key="_carDatialViewTemplate"标记的DataTemplate资源。
    ItemTemplate="{StaticResource _listBoxCars}",把每一件数据的外衣交给ListBox,当ListBox的ItemSource被赋值的时候,ListBox就会为每个条目穿上这件外衣。这件外衣是以x:Key="_listBoxCars"标记的DataTemplate资源。
    因为不再使用事件驱动,而且为数据穿衣服的事也已经自动完成,所以后台的C#代码就非常的简单。窗体的C#代码就只剩下这些:
    [csharp] view plain copy
     
     print?
    1. /// <summary>  
    2. /// wnd112.xaml 的交互逻辑  
    3. /// </summary>  
    4. public partial class wnd112 : Window  
    5. {  
    6.     List<Car> _carList;  
    7.     public wnd112()  
    8.     {  
    9.         InitializeComponent();  
    10.   
    11.         _carList = new List<Car>()  
    12.         {  
    13.             new Car(){Name = "Aodi1", ImagePath=@"/Resources/Images/Aodi.jpg", Automarker=@"/Resources/Images/01077_1.png", Year="1990"},  
    14.             new Car(){Name = "Aodi2", ImagePath=@"/Resources/Images/Aodi.png", Automarker=@"/Resources/Images/01077_1.png", Year="2001"},  
    15.         };  
    16.   
    17.         _listBoxCars.ItemsSource = _carList;  
    18.     }  
    19. }  
    运行程序,效果如下图:

    3. 控件的外衣ControlTemplate

        每每提到ControlTemplate我都会想到“披着羊皮的狼”这句话-----披上羊皮之后,虽然看上去像只羊,但其行为仍然是匹狼。狼的行为指的是它能吃别的动物、对着满月嚎叫等事情,控件也有自己的行为,比如显示数据、执行方法、激发事件等。控件的行为要靠编程逻辑来实现,所以也可以把控件的行为称为控件的算法内容。举个例子,WPF中的CheckBox与其基类ToggleButton的功能几乎完全一样,但外观差别上却非常的大,这就是更换ControlTemplate的结果。经过更换ControlTemplate,我们不但可以制作披着CheckBox外衣的ToggleButton,还能制作披着温度计外衣的ProgressBar控件。
    注意:
    实际项目中,ControlTemplate主要有两大用武之地:
    通过更换ControlTemplate来更换控件的外观,使之具有更优的用户体验和外观。
    借助ControlTemplate,程序员和设计师可以并行工作,程序员可以使用WPF标准控件进行编程,等设计师的工作完成之后,只需要把新的ControlTemplate应用的程序中即可。

        ItemsControl具有一个名为ItemsPanel的属性,它的数据类型是ItemsPanelTemplate。ItemsPanelTemplate也是一种控件Template,它的作用是可以让程序员可以控制ItemsControl的条目容器。

    举例而言,在我们的印象中ListBox中的条目都是至上而下排列的,如果客户要求我们做一个水平排列的ListBox怎么办呢?WPF之前,我们只能重写控件比较底层的方法和属性,而现在我们只需要调整ListBox的ItemsPanel属性。

    [html] view plain copy
     
     print?
    1. <Window x:Class="WpfApplication11.wnd1132"  
    2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    4.         Title="wnd1132" Height="80" Width="300">  
    5.     <Grid>  
    6.         <ListBox>  
    7.             <!--条目容器-->  
    8.             <ListBox.ItemsPanel>  
    9.                 <ItemsPanelTemplate>  
    10.                     <StackPanel Orientation="Horizontal"></StackPanel>  
    11.                 </ItemsPanelTemplate>  
    12.             </ListBox.ItemsPanel>  
    13.             <!--条目元素-->  
    14.             <TextBlock Text="Allan"></TextBlock>  
    15.             <TextBlock Text="Allan2"></TextBlock>  
    16.             <TextBlock Text="Allan3"></TextBlock>  
    17.             <TextBlock Text="Allan4"></TextBlock>  
    18.         </ListBox>  
    19.     </Grid>  
    20. </Window>  

    条目就会包装在一个水平排列的StackPanel中,从而横向排列,如下图所示:

  • 相关阅读:
    一起谈.NET技术,在MVC2.0 中 遭遇无法被 Try Catch 的 “Exception” 狼人:
    一起谈.NET技术,敏捷十年,成效几何? 狼人:
    一起谈.NET技术,ASP.NET调用.sql文件 狼人:
    一起谈.NET技术,VS 2010中内核窗户问题解析 狼人:
    一起谈.NET技术,编写T4模板无法避免的两个话题:&quot;Assembly Locking&quot;&amp;&quot;Debug&quot; 狼人:
    一起谈.NET技术,在ASP.NET网页间传递数据的五种方法 狼人:
    一起谈.NET技术,.NET平台上的JavaScript引擎 狼人:
    一起谈.NET技术,ASP.NET MVC 2中使用jQuery UI控件详解 狼人:
    一起谈.NET技术,Silverlight面向客户端,HTML5面向Web 狼人:
    一起谈.NET技术,ASP.NET MVC:自定义 Route 以生成小写的 Url 狼人:
  • 原文地址:https://www.cnblogs.com/lizhenlin/p/5906729.html
Copyright © 2020-2023  润新知