模板

在WPF中,模板可以分为两大类:

  • 控件模板(ControlTemplate)是算法内容的表现形式,一个控件怎么组织其内部的结构才能让它更符合业务逻辑,让用户操作更舒服,都是由她控制的。它决定了控件长什么样子,并让程序员有机会在控件原有的内部逻辑基础上扩展自己的逻辑。

  • 数据模板(DataTemplate)是数据内容的表现形式,一条数据表现成什么样子,是简单的文本还是直观的图形动画就由他决定。

我们先了解一下数据模板,同样一条数据比如拥有类Student实例,具有如下就一个字段:

public class Student
{
/// <summary>
/// 索引
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性别
/// </summary>
public Sex Sex { get; set; }
/// <summary>
/// 出生日期
/// </summary>
public DateTime BirthDate { get; set; }
} /// <summary>
/// 性别
/// </summary>
public enum Sex : byte
{
/// <summary>
/// 男
/// </summary>
Male = 0,
/// <summary>
/// 女
/// </summary>
Female = 1,
/// <summary>
/// 其他
/// </summary>
Other = 2,
}

这样的内容,在不同的控件中展示,展示的形式会不一样,这种模式称之为 数据-视图 模式。在WPF中,我们可以使用自定义控件UserControl来实现,也可以使用数据模板DataTemplate实现。

DataTemplate常用在下面情况下:

  • ContentControl的ContentTemplate属性,相当与给ContentControl的内容穿衣服
  • ItemsControl 的ItemTemplate属性,相当远给ItemsControl的数据条目穿衣服
  • GridViewColumn的CellTemplate属性,相当于给GridViewColumn的单元格的数据穿衣服

我么你先看一下一个程序的展示效果

这里我们看一下代码实现:

<UserControl
x:Class="LpbPrj.Client.Views.ResultWideAreaImagingView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:control="clr-namespace:LpbPrj.Client.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:langs="clr-namespace:LpbPrj.Client.Properties.Langs"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/">
<ListBox
Margin="0,0,0,0"
control:CustomeSelectionItems.SelectedItems="{Binding ResultSelectedItems}"
BorderThickness="0"
ItemsPanel="{StaticResource FluidMoveBehaviorWrapPanelItemsPanelTemplate}"
ItemsSource="{Binding ResultList}"
SelectedItem="{Binding Result}"
SelectionMode="{Binding SelectionMode}"
Style="{StaticResource WrapPanelHorizontalListBox}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<ContentControl prism:RegionManager.RegionName="ItemWideAreaImaging" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>

在这个ListBox中,我们对其中的ItemTemplate穿衣服,这个衣服的内容是:

<UserControl
x:Class="LpbPrj.Client.Views.ItemWideAreaImaging"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:langs="clr-namespace:LpbPrj.Client.Properties.Langs"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/">
<hc:Card
MaxWidth="240"
Margin="8"
BorderThickness="0"
Effect="{StaticResource EffectShadow2}"
Footer="{Binding}"
Header="{Binding}">
<hc:Card.HeaderTemplate>
<DataTemplate>
<TextBlock
Margin="5"
Style="{StaticResource TextBlockDefault}"
Text="{Binding ExamType, Converter={StaticResource DtoShowStringConverter}}" />
</DataTemplate>
</hc:Card.HeaderTemplate>
<Border CornerRadius="4,4,0,0" Style="{StaticResource BorderClip}">
<Grid>
<Image Source="{Binding ImageThumbPath, Converter={StaticResource Path2BitmapImageConverter}}" Stretch="Uniform" />
</Grid>
</Border>
<hc:Card.FooterTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel
Grid.Column="0"
Margin="5"
Orientation="Horizontal">
<TextBlock
Style="{StaticResource TextBlockDefault}"
Text="{Binding ExamFileType, Converter={StaticResource DtoShowStringConverter}}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
<TextBlock
Margin="10,0,0,0"
Style="{StaticResource TextBlockDefault}"
Text="{Binding ExamImageType, Converter={StaticResource ExamImageTypeConverter}}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
<TextBlock
Margin="10,0,0,0"
Style="{StaticResource TextBlockDefault}"
Text="{Binding EyeType, Converter={StaticResource DtoShowStringConverter}}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
</StackPanel>
<CheckBox
Grid.Column="1"
Width="30"
Height="30"
Margin="10,0,5,0"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" />
</Grid>
</DataTemplate>
</hc:Card.FooterTemplate>
</hc:Card>
</UserControl>

这段代码中的prism,我们暂且不管,但是主要内容还是能够理解的,我们使用了一个Card控件进行描述ListBox的展示内容,每个Card又通过TextBlock和CheckBox等控件进行描述。TextBlock中的对应的数据类型可能不能直接用于展示,比如枚举值,时间类型等。这里我们通过转化Converter来实现想要的展示形式。

这里面存在一个认识的误区,在上面的代码中,我们认为ListBox的Items属性里面存放的是数据而不是控件。我们可以直接将ListBox的选中属性SelectedItem绑定到一个对应的数据实例中。这种模式叫做数据驱动模式。和我们之前使用的事件驱动模式不一样。事件驱动是控件和控件之间沟通或者说是形式和形式之间的沟通,而数据驱动则是数据与控件之间的沟通,是内容和形式之间的沟通。

数据模板理解之后,我们再看一下控件模板ControlTemplate,我们可以使用披着羊皮的狼来理解控件模板,表面上看上去是羊,但是其实是狼。所以控件模板只是改变了控件的外形,不能改变控件的本质。对应控件外形的编辑我们推荐使用Blend。

我们先看一个简单的Lable标签:

<Style x:Key="LabelBaseStyle" TargetType="{x:Type Label}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.4" />
</Trigger>
</Style.Triggers>
<Setter Property="Foreground" Value="{DynamicResource TextIconBrush}" />
<Setter Property="Background" Value="{DynamicResource RegionBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrush}" />
<Setter Property="CornerRadius" Value="{StaticResource DefaultCornerRadius}" />
<Setter Property="Padding" Value="{StaticResource DefaultControlPadding}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true" CornerRadius="{Binding Path=(controls:BorderElement.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

我们对Lable标签的ControlTemplate进行修改,里面包含了一个控件Border,Border内部包含了控件的内容ContentPresenter。Border的属性通过绑定设置了BorderBrush="{TemplateBinding BorderBrush}" ,代表Border的BorderBrush属性需要绑定到Label的BorderBrush属性,两者保持一致。

深入浅出WPF-11.Template(模板)01的更多相关文章

  1. 《深入浅出WPF》笔记——模板篇

    原文:<深入浅出WPF>笔记--模板篇 我们通常说的模板是用来参照的,同样在WPF中,模板是用来作为制作控件的参照. 一.认识模板 1.1WPF菜鸟看模板 前面的记录有提过,控件主要是算法 ...

  2. c++11 template 模板练习

    直接上代码吧 to do // 111111.cpp: 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> ...

  3. 《深入浅出WPF》笔记——资源篇

    原文:<深入浅出WPF>笔记--资源篇 前面的记录有的地方已经用到了资源,本文就来详细的记录一下WPF中的资源.我们平时的“资源”一词是指“资财之源”,是创造人类社会财富的源泉.在计算机程 ...

  4. 编译器对C++ 11变参模板(Variadic Template)的函数包扩展实现的差异

    编译器对C++ 11变参模板(Variadic Template)的函数包扩展实现的差异 题目挺绕口的.C++ 11的好东西不算太多,但变参模板(Variadic Template)肯定是其中耀眼的一 ...

  5. 《深入浅出WPF》 学习笔记

    <深入浅出WPF> 序言 1. 什么是WPF    2. 为什么要学习WPF 第一章 XAML概览 1. XAML是什么? 2. XAML有哪些优点 第二章 从零起步认识XAML 1. 新 ...

  6. 微信小程序新闻列表功能(读取文件、template模板使用)

    微信小程序新闻列表功能(读取文件.template) 不忘初心,方得始终.初心易得,始终难守. 在之前的项目基础上进行修改,实现读取文件内容作为新闻内容进行展示. 首先,修改 post.wxml 文件 ...

  7. ArcGIS API for Silverlight代码中使用Template模板

    原文:ArcGIS API for Silverlight代码中使用Template模板 在项目开发中,会遇到点选中聚焦闪烁效果,但是因为在使用Symbol的时候,会设置一定的OffSetX和OffS ...

  8. WPF 详解模板

    在WPF中有三大模板 ControlTemplate,ItemsPanelTemplate,DataTemplate.其中ControlTemplate和 ItemsPanelTemplate是控件模 ...

  9. 【【分享】深入浅出WPF全系列教程及源码 】

    因为原书作者的一再要求,在此声明,本书中的部分内容引用了原书名为<深入浅出WPF>的部分内容,假设博文不能满足你现有的学习须要,能够购买正版图书! 本人10月份提出离职,可是交接非常慢,预 ...

  10. 《深入浅出WPF》笔记——绘画与动画

    <深入浅出WPF>笔记——绘画与动画   本篇将记录一下如何在WPF中绘画和设计动画,这方面一直都不是VS的强项,然而它有一套利器Blend:这方面也不是我的优势,幸好我有博客园,能记录一 ...

随机推荐

  1. Qt简单的解析Json数据例子(一)

    要解析的json的格式为: { "rootpath": "001", "usernum": 111, "childdep" ...

  2. vue去掉一些烦人的校验规则

    例如:括号前没有加空格报错,很难受 如何处理呢,故意犯错,然后打开页面出现错误信息,如下图复制错误 space-before-function-paren 找到项目中的.eslintrc.js 添加一 ...

  3. jQuery中的样式(七):addClass()、removeClass()、toggleClass()、hasClass()、css()、width()、height()等

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  4. Web应用安全防护-WAF

    web应用开发中不可避免需要考虑web应用的安全问题,那么常见的安全风险包含哪些呢? Web应用常见的安全风险 在web应用开发中可能存在以下的安全风险: 安全风险Top 10 A1:2017-注入 ...

  5. RabbitMQ从零到集群高可用(.NetCore5.0) - 死信队列,延时队列

    系列文章: RabbitMQ从零到集群高可用(.NetCore5.0) - RabbitMQ简介和六种工作模式详解 RabbitMQ从零到集群高可用(.NetCore5.0) - 死信队列,延时队列 ...

  6. spring AOP事务

    1 <bean id="tttt" class="com.ry.project.dataSouces.UserLogger"/> 2 <aop ...

  7. 存储系统管理(二)——Linux系统的swap分区、磁盘加密、磁盘阵列

    磁盘驱动器上的空间 , 用作当前未使用部分内存的溢出.这样 , 系统就能在主内存中留出空间用于储存当前正在处理的数据 , 并在系统面临主内存空间不足的风险时提供应急溢出. swap分区的建立: fdi ...

  8. GetX代码生成IDEA插件,超详细功能讲解(透过现象看本质)

    前言 本文章不是写getx框架的使用,而且其代码生成IDEA插件的功能讲解 我之前写过俩篇很长很长的getx文章 一篇入门使用:Flutter GetX使用---简洁的魅力! 一篇原理深度剖析:Flu ...

  9. python glob.glob()

    glob()函数可以将某目录下所有跟通配符模式相同的文件放到一个列表中,有了这个函数,我们再想生成所有文件的列表就不需要使用for循环遍历目录了,直接使用glob.glob(path+pattern) ...

  10. C#中的“等待窗体”对话框

    这篇文章向您展示了如何在c#.net Windows窗体应用程序中创建一个等待窗体对话框.创建一个新表单,然后输入您的表单名称为frmWaitForm.接下来,将Label,Progress Bar控 ...