上一篇关于模板的文章:
《深入浅出WPF》—— Data / Control 模板的使用(一)
为 Template 设置其应用目标有两种方法:
- 一种是逐个设置控件的 Template / ContentTemplate 等属性,不想应用则不设置(上一文用)
- 一种是
整体应用
,即把 Template应用在某个控件或数据上
文章目录
ControlTemplate的应用
把 ControlTemplate 应用在所有目标上需要借助 Style 来实现,但 Style 不能标记 x:Key
例如下面的代码:
<Window x:Class="WpfApp31.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="150" Width="230">
<Window.Resources>
<Style TargetType="{x:Type TextBox}">
// *************************************** //
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" CornerRadius="20" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
// *************************************** //
<Setter Property="Margin" Value="5"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Height" Value="25"/>
<Setter Property="Background" Value="LightBlue"/>
</Style>
</Window.Resources>
<StackPanel>
<TextBox/>
<TextBox/>
<TextBox Style="{x:Null}" Background="Black"/>
</StackPanel>
</Window>
(注
:核心部分我已经用 // *** // 标记 . . .)
我们发现,控件模块就是修改了一些风格而已,并且作用于指定的类型
Style 没有 x:Key标记,默认为应用到所有由 x:Type指定的控件上,如果不需要则把 Style设置 {x:null}。
效果如下:
其中,前两个 TextBox为默认风格,第三个 Style为 null . . .
DataTemplate的应用
把 DataTemplate 应用在某个数据类型上的方法是设置 DataTemplate 的 Data属性,并且把 DataTemplate 作为资源时也不能带有 x:Key标记。
很多时候数据是以 XML形式存储的,因为这样做很方便。DataTemplate 很智能,具有直接把 XML数据结点当作目标对象的功能 ——
XML 数据中的元素名(标签名)可以作为 DataType
,元素的子结点 和 Attribute 可以使用 XPath来访问。
我们需要完成上一文中类似的数据柱形图:参考开头的链接
下面的代码使用 XmlDataProvider 作为数据源(XPath 必需指出一组结点:Units/Unit ):
<Window x:Class="WpfApp33.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataTemplate" SizeToContent="WidthAndHeight">
<Window.Resources>
// *************************************************//
<DataTemplate DataType="Unit">
<Grid>
<StackPanel Orientation="Horizontal">
<Grid>
<Rectangle Stroke="Yellow" Fill="Orange"
Width="{Binding XPath=@Price}"/>
<TextBlock Text="{Binding XPath=@Year}"/>
</Grid>
<TextBlock Text="{Binding XPath=@Price}" Margin="5,0"/>
</StackPanel>
</Grid>
</DataTemplate>
// *************************************************//
<XmlDataProvider x:Key="ds" XPath="Units/Unit">
<x:XData>
<Units xmlns="">
<Unit Year ="2001" Price="100"/>
<Unit Year ="2002" Price="120"/>
<Unit Year ="2003" Price="140"/>
<Unit Year ="2004" Price="150"/>
<Unit Year ="2005" Price="130"/>
<Unit Year ="2006" Price="160"/>
</Units>
</x:XData>
</XmlDataProvider>
// *************************************************//
</Window.Resources>
<StackPanel>
<ListBox ItemsSource="{Binding Source={StaticResource ds}}"/>
<ComboBox ItemsSource="{Binding Source={StaticResource ds}}" Margin="5"/>
</StackPanel>
</Window>
代码分为三部分:
- 定义DataTemplate,指定 DataType, —
@表示引入xml结点的特性 . . .
- XmlDataProvider,提供数据
- 引用数据,数据被默认添加模板
结果图如下:
HierarchicalDataTemplate的应用
XML最大的优势是可以方便地表示带有层级的数据
,比如:
- 年级 --> 班级 --> 小组
- 主菜单 --> 次级菜单 --> 三级菜单
同时,WPF准备了 TreeView
和 MenuItem
控件用来显示 层级数据
。能够帮助层级控件显示层级数据的模板是 HierarchicalDataTemplate
。
下面我们将举两个例子来测试一下它们 . . .
TreeView使用
使用 TreeView显示多层级、不同类型数据。因为数据类型不同,所以我们需要为每种数据设计一个模板,这就可以将每种数据类型表示独有的外观。
为了方便,我们将数据直接向上面一样,定义在XAML代码中,日常项目中,我们可以写在单独的 xml文件中. . .
<Window x:Class="WpfApp34.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataTemplate" SizeToContent="WidthAndHeight">
<Window.Resources>
//********************************************//
<XmlDataProvider x:Key="ds" XPath="Data/Grade">
<x:XData>
<Data xmlns="">
<Grade Name ="一年级">
<Class Name="甲班">
<Group Name="A 组"/>
<Group Name="B 组"/>
<Group Name="C 组"/>
</Class>
<Class Name="乙班">
<Group Name="A 组"/>
<Group Name="B 组"/>
<Group Name="C 组"/>
</Class>
</Grade>
<Grade Name ="二年级">
<Class Name="甲班">
<Group Name="A 组"/>
<Group Name="B 组"/>
<Group Name="C 组"/>
</Class>
<Class Name="乙班">
<Group Name="A 组"/>
<Group Name="B 组"/>
<Group Name="C 组"/>
</Class>
</Grade>
</Data>
</x:XData>
</XmlDataProvider>
//********************************************//
<HierarchicalDataTemplate DataType="Grade" ItemsSource="{Binding XPath=Class}">
<TextBlock Text="{Binding XPath=@Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="Class" ItemsSource="{Binding XPath=Group}">
<RadioButton Content="{Binding XPath=@Name}" GroupName="gn"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="Group" ItemsSource="{Binding XPath=Student}">
<CheckBox Content="{Binding XPath=@Name}"/>
</HierarchicalDataTemplate>
//********************************************//
</Window.Resources>
<Grid>
<TreeView Margin="5" ItemsSource="{Binding Source={StaticResource ds}}"/>
</Grid>
</Window>
代码分为三部分:
- 使用 XmlDataProvider 定义树形数据,年级 --> 班级 --> 小组
- 使用层级模板 HierarchicalDataTemplate,表示显示的数据模样
- 使用 TreeView 调用资源数据
效果如下:
MenuItem使用
下面的例子是同一种数据类型的嵌套结构,我们只需要设计一个 HierarchicalDataTemplate 就可以了,它会产生自动迭代应用的效果。
像上面一样,数据仍然放在 XAML中,代码如下:
<Window x:Class="WpfApp35.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="HierarchicalDataTemplate " Height="300" Width="300">
<Window.Resources>
<XmlDataProvider x:Key="ds" XPath="Data/Operation">
<x:XData>
<Data xmlns="">
<Operation Name="文件" Gesture="F">
<Operation Name="新建" Gesture="N">
<Operation Name="项目" Gesture ="Control + P"/>
<Operation Name="网站" Gesture ="Control + W"/>
<Operation Name="文档" Gesture ="Control + D"/>
</Operation>
<Operation Name="保存" Gesture="S"/>
<Operation Name="剪切" Gesture="P"/>
<Operation Name="退出" Gesture="X"/>
</Operation>
<Operation Name="编辑" Gesture="E">
<Operation Name="拷贝" Gesture ="Control + C"/>
<Operation Name="剪切" Gesture ="Control + X"/>
<Operation Name="粘贴" Gesture ="Control + V"/>
</Operation>
</Data>
</x:XData>
</XmlDataProvider>
<HierarchicalDataTemplate DataType="Operation"
ItemsSource="{Binding XPath=Operation}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding XPath=@Name}" Margin="10,0"/>
<TextBlock Text="{Binding XPath=@Gesture}"/>
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<StackPanel
<Menu x:Name="m" ItemsSource="{Binding Source={StaticResource ds}}"/>
</StackPanel>
</Window>
和上面的 TreeView一样,都是先定义数据,然后使用层级模板修饰数据,最后引用数据 . . .