原文: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模板(二)应用相关推荐

  1. 10-1.WPF模板

    10-1.WPF模板 控件由"算法内容"和"数据内容"决定 算法内容:指控件能展示哪些数据.具有哪些方法.能激发什么事件等,简而言之是控件的功能,一组相关逻辑 ...

  2. 【转载】WPF快速入门系列(7)——深入解析WPF模板

    一.引言 模板从字面意思理解是"具有一定规格的样板".在现实生活中,砖块都是方方正正的,那是因为制作砖块的模板是方方正正的,如果我们使模板为圆形的话,则制作出来的砖块就是圆形的,此 ...

  3. Xamarin XAML语言教程构建ControlTemplate控件模板 (二)

    Xamarin XAML语言教程构建ControlTemplate控件模板 (二) (2)打开MainPage.xaml文件,编写代码,将构建的控件模板应用于ContentView中.代码如下: &l ...

  4. WPF 开源二维绘画小工具 GeometryToolDemo 项目

    这是一个演示 WPF 进行二维绘画的小工具 Demo 项目,基于 MIT 协议在 GitHub 上完全开源 源作者是 YuWeiCong 我只是帮助开源的工具人 软件运行界面效果: 开源地址: htt ...

  5. 《信息化项目文档模板二——项目启动会文档模板》

    系列文章目录 <信息化项目文档模板一--项目需求说明书> <信息化项目文档模板二--项目启动会文档模板> <信息化项目文档模板三--会议纪要模板> <信息化项 ...

  6. Visual Studio 2019 STK11.6 C#(WPF)二次开发

    Visual Studio 2019 STK11.6 C#(WPF)二次开发 概述 环境 软件效果 工程创建 添加引用文件 主要代码 1.创建场景 2.创建飞机 3.创建站点 4.创建传感器 5.创建 ...

  7. WPF入门第四篇 WPF模板

    WPF模板 1.ControlTemplate 上一篇已经试用过控件模板,我们知道WPF的控件都是继承自Control,在Control类中有一个Template属性,类型就是ControlTempl ...

  8. 金蝶K3Cloud 5.0 套打设计模板 二维码

    金蝶K3Cloud 5.0 套打设计模板 二维码 找了很久没找到,做个记录 条形码-属性-设置-编码: 另外K3这里的控件不能旋转,唉

  9. WPF补充(二) 资源(Resource)

    一.什么是资源 通常使用 WPF 资源作为重用通常定义的对象和值的简单方法. 例如定义一种可以复用的单色的Brush对象,按钮的背景及矩形的填充颜色均使用此Brush: <Window x:Cl ...

最新文章

  1. 关于程序员就业岗位及岗位市场的思考
  2. php对提交数据转码,如何使用php程序实现媒体转码消息的接收
  3. MySQL数据库管理(二)单机环境下MySQL Cluster的安装
  4. Package Manager Console 向VS2010安装 EntityFramework
  5. wxWidgets:wxRearrangeDialog类用法
  6. C#使用 System.Net.Mail发送邮件功能
  7. 网易试题——关于箭头函数与this和arguments的关系
  8. 深入async/await知多少
  9. hibernate学习---用Session实现CURD
  10. 样本不平衡问题分析与部分解决办法
  11. 微观经济学第七周作业(生产函数,规模报酬,投入产出)
  12. 公司员工后台管理系统界面设计-Axure9原型设计
  13. java实现word转换pdf并批量生成水印
  14. Kubernetes(k8s)四、Pod生命周期(初始化容器的应用,探针liveness、readliness应用,)
  15. Invalid packaging for parent POM x, must be “pom“ but is “jar“ @
  16. 【MyBatis】 动态SQL——模糊查询 LIKE
  17. Scikit-Learn 中文文档】数据集加载工具 - 用户指南 | ApacheCN
  18. python-onvif 库踩坑
  19. hackthebox-Tracks-Beginner_Track-Lame
  20. 电子秤称东西用计算机怎么算,怎样将电子天平或电子秤连接到PC并直接将重量值读取到Excel中...

热门文章

  1. OVS技术介绍(四十一)
  2. whoami,who,w命令详解
  3. 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截...
  4. c++删除容器中的奇数
  5. 实现当UILable的内容超出其范围后自动滚动效果
  6. 细数C++和C的差别
  7. Java多线程详解(二)
  8. OPEN RESETLOGS 启动,报ORA-00392   ORA-00312错误
  9. socket 编程入门教程(一)TCP server端:3、sockaddr与sockaddr_in
  10. 水杯测试----误人子弟啊!