模板

在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. Java常用类之时间类

    JDK8之前日期时间API 1. java.lang.System类 2. java.util.Date类 3. java.text.SimpleDateFormat类 4. java.util.Ca ...

  2. SpringBoot整合Quartz定时任务(持久化到数据库)

    背景 最近在做项目,项目中有个需求:需要使用定时任务,这个定时任务需要即时生效.查看Quartz官网之后发现:Quartz提供两种基本作业存储类型: RAMJobStore :RAM也就是内存,默认情 ...

  3. WebAPI中controller添加[AllowAnonymous]无效的解决方法

    对于Methods添加[AllowAnonymous]可以进行匿名访问,但是对于Controller添加时无效 public class AuthAttribute : AuthorizationFi ...

  4. 原生 JS 与 jQuery 中的 AJAX

    AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更 ...

  5. 地图控件:overview、scale、toolbar

    地图常用控件: 1.AMap.MapType:地图类型切换插件,用来切换固定的几个常用图层 2.AMap.OverView:地图鹰眼插件,默认在地图右下角显示缩略图 3.AMap.Scale:地图比例 ...

  6. 并发编程之:AQS源码解析

    大家好,我是小黑,一个在互联网苟且偷生的农民工. 在Java并发编程中,经常会用到锁,除了Synchronized这个JDK关键字以外,还有Lock接口下面的各种锁实现,如重入锁ReentrantLo ...

  7. 理解ASP.NET Core - [03] Dependency Injection

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 依赖注入 什么是依赖注入 简单说,就是将对象的创建和销毁工作交给DI容器来进行,调用方只需要接 ...

  8. (六)羽夏看C语言——函数

    写在前面   由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...

  9. 机械硬盘换到SSD后系统引导报错代码0xc000000e

    由于机械硬盘IO不够用,系统使用起来非常的缓慢,特意购买了新的SSD进行了替换.机械硬盘的IO在70左右,SSD的IO在1000-4000左右指普通消费SSD. 由于不想安装系统,就直接把机械硬盘的数 ...

  10. Appium自动化(16) - 使用手机浏览器进行自动化测试

    如果你还想从头学起Appium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1693896.html 前言 前面我都讲的都是针对 app ...