WPF模板(二)应用
本次内容来源于电子书,和上一篇一样。
在WPF中有三大模板ControlTemplate,ItemsPanelTemplate,DataTemplate.其中ControlTemplate和ItemsPanelTemplate是控件模板,DataTemplate是数据模板,他们都派生自FrameworkTemplate抽象类。
1、ControlTemplate
ControlTemplate:控件模板主要有两个重要属性:VisualTree内容属性和Triggers触发器。所谓VisualTree(视觉树),就是呈现我们所画的控件。Triggers可以对我们的视觉树上的元素进行一些变化。一般用于单内容控件。
画一个按钮模板来举例说明:
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Width="100" Height="100">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="blue"/>
<GradientStop Offset="1" Color="LightBlue"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse Width="80" Height="80">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="White"/>
<GradientStop Offset="1" Color="Transparent"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Button Content="Hello WPF"/>
结果:
ControlTemplate之子 ContentControl和ContentPresenter
我们在ControlTemplate中画了两个椭圆,应用于所有的Button按钮,但我们Button中有Content属性(内容为Hello WPF),却没有显示出来。因为这里用ControlTemplate重写了Button的样式,所以我们也要在ControlTemplate中增加ContentControl。通过ContentControl中的Content来绑定父容器的Content属性。
<Style TargetType="Button"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="Button"><Grid><Ellipse Width="100" Height="100"><Ellipse.Fill><LinearGradientBrush StartPoint="0,0" EndPoint="0,1"><GradientStop Offset="0" Color="blue"/><GradientStop Offset="1" Color="LightBlue"/></LinearGradientBrush></Ellipse.Fill></Ellipse><Ellipse Width="80" Height="80"><Ellipse.Fill><LinearGradientBrush StartPoint="0,0" EndPoint="0,1"><GradientStop Offset="0" Color="White"/><GradientStop Offset="1" Color="Transparent"/></LinearGradientBrush></Ellipse.Fill></Ellipse><ContentControl VerticalAlignment="Center" HorizontalAlignment="Center" Content="{TemplateBinding Content}"/></Grid></ControlTemplate></Setter.Value></Setter></Style>
这下内容出来了
我们来看一下,ContentControl继承于Control的,用MSDN的话是:表示包含单项内容的控件、ContentControl 可以包含任何类型的公共语言运行库对象。如下ContentControl类图。
为了提高性能,我们可以用一个ControlPresenter来代替ContentControl,效果还是一样,那他们有什么区别呢?
来看下ControlPresenter这个类,它继承于FreameworkElement,如下图:
ControlPresenter 通常叫做内容占位符。所以我们可以看到
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>来代替<ContentControl VerticalAlignment="Center" HorizontalAlignment="Center" Content="{TemplateBinding Content}"/> 。这里少了Content绑定父容器,因为ControlPresenter有个隐式的Content="{TemplateBinding Content}",也就是你可以写也可以不写它。
从他们的基类可以看出,ContentControl比ContentPresenter大多了。其实ControlPresenter是一个原始的构建块,而ContentControl是一个带控件模板的成熟控件(里面包含ControlPresenter)。
所以我们一般用ControlPresenter。
ControlTemplate的VisualTree我们讲过了,下面看下他的trigger如何运用。
我们在原来的代码中增加
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="ellipse1" Property="Fill" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
当我们把鼠标移上去的时候就会变成如下图所示:
发挥我们的想象力,我们可以根据ControlTemplate做更多的特效。如下
<Style TargetType="CheckBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<DockPanel>
<ContentPresenter DockPanel.Dock="Left" VerticalAlignment="Center" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="0" Grid.ColumnSpan="2" Fill="Gray"/>
<TextBlock x:Name="txtBox" Foreground="White" />
</Grid>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="txtBox" Property="Grid.Column" Value="1"/>
<Setter TargetName="txtBox" Property="Text" Value="On"/>
<Setter TargetName="txtBox" Property="Background" Value="LightBlue"/>
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter TargetName="txtBox" Property="Grid.Column" Value="0"/>
</Trigger>
<Trigger Property="IsChecked" Value="false">
<Setter TargetName="txtBox" Property="Grid.Column" Value="0"/>
<Setter TargetName="txtBox" Property="Text" Value="OFF"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Grid>
<CheckBox Width="100" Height="30" Content="Click Me"/>
</Grid>
效果图:点击之前点击之后
2、ItemsPanelTemplate
ItemsPanelTemplate在MSDN的解释是:ItemsPanelTemplate 指定用于项的布局的面板。 GroupStyle 具有一个类型为 ItemsPanelTemplate 的 Panel属性。 ItemsControl 类型具有一个类型为ItemsPanelTemplate 的 ItemsPanel 属性。
我们先讲ItemTemplate。它一般用在多个内容控件的模板。比如ListBox。
如下看ListBox应用ItemTemplate:
在xaml中
<Style TargetType="ListBox"><Setter Property="ItemTemplate"><Setter.Value><DataTemplate><Image Source="{Binding UriSource}" Width="100" Height="100"/> </DataTemplate> </Setter.Value> </Setter> </Style>
<ListBox x:Name="listBox" />
在后台代码我们给它一些图片来填充这个ListBox.
public partial class ListBoxUserControl : UserControl{public ListBoxUserControl(){InitializeComponent();listBox.ItemsSource = LoadImages();}public List<BitmapImage> LoadImages(){List<BitmapImage> bitmapImages=new List<BitmapImage>();DirectoryInfo directoryInfo = new DirectoryInfo(@"E:\WPFDEMO\ControlTest\ControlTest\Images");foreach (var item in directoryInfo.GetFiles("*.jpg")){Uri uri=new Uri(item.FullName);bitmapImages.Add(new BitmapImage(uri));}return bitmapImages;}}
每一张图片就是一个Item。
我们如果想让图片以横向显示。一开始我以为用StackPanel的Orientation=”Horiziontal”,发现犯了个错误。这样设置是现在把Items中某一个item中的内容水平显示啊。这时就要用到ItemsPanelTemplate这个模板了。我们在ListBox的样式中增加如下红色区域的代码:
<Style TargetType="ListBox"><Setter Property="ItemTemplate"><Setter.Value><DataTemplate><StackPanel Orientation="Horizontal"><Image Source="{Binding UriSource}" Width="100" Height="100"/> <TextBlock Text="qq" Background="Red"/> </StackPanel> </DataTemplate> </Setter.Value> </Setter>
<Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <StackPanel /> </ItemsPanelTemplate> </Setter.Value> </Setter>
</Style>
这里我在DataTemplate中加了StackPanel 为了说明加在这里的效果只是区分:Items整体横向和Item中内容的区别。
现在我们要想让布局可以随着窗体宽度变化,我们只要把ItemsPanelTemplate中的StackPanel 改成WrapPanel,并且设置ListBox的ScrollViewer.HorizontalScrollBarVisibility="Disabled",这样才可以看到效果。
ControlTemplate
之 ItemsPresenter和ContentPresenter
我们先构造一个TreeView
xaml中:
在开始加个Loaded="UserControl_Loaded"
<Grid>
<TreeView x:Name="treeview" />
</Grid>
后台代码中:
public class Node{private IList<Node> _childNodes;private string _name;public Node(){}public Node(string name){_name = name;}public string Name{get { return _name; }set { _name = value; }}public IList<Node> ChildNodes{get{if (_childNodes==null)_childNodes=new List<Node>();return _childNodes;}}}public partial class TreeViewUserControl : UserControl{public TreeViewUserControl(){InitializeComponent();}private void UserControl_Loaded(object sender, RoutedEventArgs e){treeview.PreviewKeyDown += (o,a) => { a.Handled = true; };PopulateTreeView();}void PopulateTreeView(){Node rootNode=new Node("GrandFather");for (int i = 0; i < 2; i++){Node child=new Node("Father");rootNode.ChildNodes.Add(child);for (int j = 0; j < 3; j++){Node child2=new Node("Son");child.ChildNodes.Add(child2);}}Node dummy=new Node();dummy.ChildNodes.Add(rootNode);treeview.ItemsSource = dummy.ChildNodes;}}
没有任何样式的TreeView
下面我们如何运用ItemsPresenter和ContentPresenter来添加样式。来实现下面这幅图的效果
在TreeView中ItemsPresenter和ContentPresenter是什么关系:ContentPresenter
是用来显示TreeView中Item的内容 。ItemsPresenter
是用来显示它的子项(Item的子项,也就是说child’s Items)。
<Style TargetType="TreeViewItem"><Style.Resources><LinearGradientBrush x:Key="ItemAreaBrush" StartPoint="0,0.5" EndPoint="0.5,1"><GradientStop Offset="0" Color="#66000000"/><GradientStop Offset="1" Color="#22000000"/></LinearGradientBrush><LinearGradientBrush x:Key="SelectedItemAreaBrush" StartPoint="0.5, 0" EndPoint="0.5, 1"><GradientStop Color="Orange" Offset="0" /><GradientStop Color="OrangeRed" Offset="1" /></LinearGradientBrush><LinearGradientBrush x:Key="ItemBorderBrush" StartPoint="0.5, 0" EndPoint="0.5, 1"><GradientStop Color="LightGray" Offset="0" /><GradientStop Color="Gray" Offset="1" /></LinearGradientBrush><LinearGradientBrush x:Key="SelectedItemBorderBrush" StartPoint="0.5, 0" EndPoint="0.5, 1"><GradientStop Color="Yellow" Offset="0" /><GradientStop Color="Black" Offset="1" /></LinearGradientBrush><DropShadowBitmapEffect x:Key="DropShadowEffect"/></Style.Resources><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="TreeViewItem"><Grid Margin="2"><Grid.RowDefinitions><RowDefinition Height="auto"/><RowDefinition Height="*"/></Grid.RowDefinitions><Border x:Name="border" Background="{StaticResource ResourceKey=ItemAreaBrush}" BorderBrush="{StaticResource ItemBorderBrush}" BorderThickness="1" CornerRadius="8" Padding="6"><ContentPresenter ContentSource="Header" VerticalAlignment="Center" HorizontalAlignment="Center"/></Border><ItemsPresenter Grid.Row="1"/></Grid><ControlTemplate.Triggers><Trigger Property="IsSelected" Value="true"><Setter TargetName="border" Property="Panel.Background" Value="{StaticResource SelectedItemAreaBrush}"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter><Setter Property="ItemsPanel"><Setter.Value><ItemsPanelTemplate><StackPanel Orientation="Horizontal" HorizontalAlignment="Center" IsItemsHost="True"/></ItemsPanelTemplate></Setter.Value></Setter></Style>
看红色代码的部分,这里ContentPresenter显示了父容器的Header的内容,比如GrandFather,Father,Son.而ItemsPresenter则是否让他显示其子元素。比如GrandFather的子元素为Father,没有设置<ItemsPresenter Grid.Row="1"/> 的话。子元素Father是不会显示的。
这里为了突出层次化,运用了ItemsPanelTemplate。最后我们在资源里引用这个样式。
<UserControl.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="/Controls/TreeViewItemStyle.xaml"/></ResourceDictionary.MergedDictionaries><HierarchicalDataTemplate DataType="{x:Type controls:Node}" ItemsSource="{Binding ChildNodes}"><TextBlock Text="{Binding Name}"/></HierarchicalDataTemplate></ResourceDictionary></UserControl.Resources>
3、DataTemplate和HierarchicalDataTemplate
DataTemplate就是显示绑定数据对象的模板。
HierarchicalDataTemplate继承于DataTemplate,它专门对TreeViewItem 或 MenuItem的一些数据对象的绑定。
WPF模板(二)应用相关推荐
- 10-1.WPF模板
10-1.WPF模板 控件由"算法内容"和"数据内容"决定 算法内容:指控件能展示哪些数据.具有哪些方法.能激发什么事件等,简而言之是控件的功能,一组相关逻辑 ...
- 【转载】WPF快速入门系列(7)——深入解析WPF模板
一.引言 模板从字面意思理解是"具有一定规格的样板".在现实生活中,砖块都是方方正正的,那是因为制作砖块的模板是方方正正的,如果我们使模板为圆形的话,则制作出来的砖块就是圆形的,此 ...
- Xamarin XAML语言教程构建ControlTemplate控件模板 (二)
Xamarin XAML语言教程构建ControlTemplate控件模板 (二) (2)打开MainPage.xaml文件,编写代码,将构建的控件模板应用于ContentView中.代码如下: &l ...
- WPF 开源二维绘画小工具 GeometryToolDemo 项目
这是一个演示 WPF 进行二维绘画的小工具 Demo 项目,基于 MIT 协议在 GitHub 上完全开源 源作者是 YuWeiCong 我只是帮助开源的工具人 软件运行界面效果: 开源地址: htt ...
- 《信息化项目文档模板二——项目启动会文档模板》
系列文章目录 <信息化项目文档模板一--项目需求说明书> <信息化项目文档模板二--项目启动会文档模板> <信息化项目文档模板三--会议纪要模板> <信息化项 ...
- Visual Studio 2019 STK11.6 C#(WPF)二次开发
Visual Studio 2019 STK11.6 C#(WPF)二次开发 概述 环境 软件效果 工程创建 添加引用文件 主要代码 1.创建场景 2.创建飞机 3.创建站点 4.创建传感器 5.创建 ...
- WPF入门第四篇 WPF模板
WPF模板 1.ControlTemplate 上一篇已经试用过控件模板,我们知道WPF的控件都是继承自Control,在Control类中有一个Template属性,类型就是ControlTempl ...
- 金蝶K3Cloud 5.0 套打设计模板 二维码
金蝶K3Cloud 5.0 套打设计模板 二维码 找了很久没找到,做个记录 条形码-属性-设置-编码: 另外K3这里的控件不能旋转,唉
- WPF补充(二) 资源(Resource)
一.什么是资源 通常使用 WPF 资源作为重用通常定义的对象和值的简单方法. 例如定义一种可以复用的单色的Brush对象,按钮的背景及矩形的填充颜色均使用此Brush: <Window x:Cl ...
最新文章
- 关于程序员就业岗位及岗位市场的思考
- php对提交数据转码,如何使用php程序实现媒体转码消息的接收
- MySQL数据库管理(二)单机环境下MySQL Cluster的安装
- Package Manager Console 向VS2010安装 EntityFramework
- wxWidgets:wxRearrangeDialog类用法
- C#使用 System.Net.Mail发送邮件功能
- 网易试题——关于箭头函数与this和arguments的关系
- 深入async/await知多少
- hibernate学习---用Session实现CURD
- 样本不平衡问题分析与部分解决办法
- 微观经济学第七周作业(生产函数,规模报酬,投入产出)
- 公司员工后台管理系统界面设计-Axure9原型设计
- java实现word转换pdf并批量生成水印
- Kubernetes(k8s)四、Pod生命周期(初始化容器的应用,探针liveness、readliness应用,)
- Invalid packaging for parent POM x, must be “pom“ but is “jar“ @
- 【MyBatis】 动态SQL——模糊查询 LIKE
- Scikit-Learn 中文文档】数据集加载工具 - 用户指南 | ApacheCN
- python-onvif 库踩坑
- hackthebox-Tracks-Beginner_Track-Lame
- 电子秤称东西用计算机怎么算,怎样将电子天平或电子秤连接到PC并直接将重量值读取到Excel中...
热门文章
- OVS技术介绍(四十一)
- whoami,who,w命令详解
- 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截...
- c++删除容器中的奇数
- 实现当UILable的内容超出其范围后自动滚动效果
- 细数C++和C的差别
- Java多线程详解(二)
- OPEN RESETLOGS 启动,报ORA-00392 ORA-00312错误
- socket 编程入门教程(一)TCP server端:3、sockaddr与sockaddr_in
- 水杯测试----误人子弟啊!