兰州网站建设小程序镇江市网站
WPF控件模版数据模板
- 控件模板(ControlTemplate)
- 定义方式
- 内联定义(直接写在ListBox中)
- 资源字典中定义
- 定义方式区别
- TemplateBinding 用法
- 对比普通Binding的区别
- 常见误区
- 何时使用
- 数据模板(DataTemplate)
- 定义与用途
- 主要应用控件
- ItemsControl及其派生控件
- ListBox
- ListView
- ComboBox
- ContentControl及其派生控件
- Button、Label、Window
- TabItem
- 其他特殊场景控件
- TreeView
- DataGrid(需手动配置)
- 动态模板选择
之前的篇章虽然有提到过 控件模版和数据模板,但是这里还是要重点在讲解一下。
控件模板(ControlTemplate)
-
定义与用途
作用:控件模板用于定义控件的可视化结构和行为,允许完全自定义控件的外观,而不影响其功能。例如,将默认的矩形按钮改为圆形,并自定义其悬停、点击效果。 -
应用场景:需要修改控件的视觉布局(如替换按钮的默认外观),或调整控件的组成部分(如添加动画、调整状态变化逻辑)。
-
关键特性
TargetType:指定模板适用的控件类型(如Button、ListBox)。
视觉状态(Visual States):通过VisualStateManager定义控件在不同状态(如MouseOver、Pressed)下的外观变化。
必需元素:需保留控件的功能逻辑。例如,按钮的ContentPresenter用于显示内容,若省略则内容无法显示
定义方式
内联定义(直接写在ListBox中)
若将ControlTemplate直接内联到ListBox的Template属性中(如示例代码),则该模板仅作用于当前ListBox实例。这种写法不会影响其他ListBox控件的外观,属于局部应用
<ListBox><ListBox.Template><ControlTemplate TargetType="ListBox"><!-- 自定义模板内容 --></ControlTemplate></ListBox.Template>
</ListBox>
特点:
无x:Key标识,直接绑定到当前控件的Template属性。
修改仅限当前控件,不影响其他ListBox实例
资源字典中定义
若将ControlTemplate定义在资源字典(如Window.Resources或全局资源文件)中,其作用范围由以下两种方式决定
- 显式指定x:Key
通过x:Key标识的模板需手动引用,适用于需要复用的场景
特点:
必须通过StaticResource或DynamicResource显式引用。
仅作用于手动引用该模板的ListBox。
<Window.Resources><ControlTemplate x:Key="CustomListBoxTemplate" TargetType="ListBox"><!-- 模板内容 --></ControlTemplate>
</Window.Resources><ListBox Template="{StaticResource CustomListBoxTemplate}"/>
- 隐式样式(无x:Key)
若定义模板时省略x:Key并指定TargetType=“ListBox”,该模板会隐式作用于所有同类型控件(即所有未显式指定模板的ListBox)
特点:
覆盖所有ListBox的默认样式。
需通过TargetType匹配控件类型,适用于统一全局风格
<Window.Resources><Style TargetType="ListBox"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="ListBox"><!-- 全局模板内容 --></ControlTemplate></Setter.Value></Setter></Style>
</Window.Resources>
定义方式区别
TemplateBinding 用法
TemplateBinding 是一个将模板内部元素的属性与目标控件属性动态关联的关键机制。
TemplateBinding Background 用最通俗的话来说,它相当于在模板中对目标控件说:"你的Background属性值是多少,我就用多少,按下面图片列子就是 Ellipse的填充颜色根据模板button的背景来,设置红色那填充就是红色
<Button Content="Click Me"><Button.Template><ControlTemplate TargetType="Button"><Grid><!-- 椭圆背景绑定到按钮的Background --><Ellipse Fill="{TemplateBinding Background}" Stroke="Black"/><!-- 内容区域绑定到按钮的Content --><ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/></Grid></ControlTemplate></Button.Template>
</Button>
对比普通Binding的区别
其实用普通的binding 也能实现 比如下面这俩个写法 效果一样的
<Border Background="{TemplateBinding Background}"/>
<Border Background="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}"/>
而TemplateBinding实际上是这种写法的简化版,只适用于控件模板内部,且语法更简洁
常见误区
- 误以为自动继承属性
有人认为模板内部元素会自动继承宿主控件的属性,但实际必须显式使用TemplateBinding建立关联。 - 忽略目标类型限制
如果宿主控件(如Button)没有某个属性(例如Fill),则模板内部无法通过TemplateBinding绑定该属性。 - 忘记TargetType
在定义ControlTemplate时,必须指定TargetType(如TargetType=“Button”),否则TemplateBinding可能无法正确解析属性
何时使用
- 需要动态同步属性:如按钮的Background、BorderThickness等需要根据宿主控件状态变化;
- 简化模板代码:避免冗长的RelativeSource绑定;
- 性能敏感场景:在需要高频更新属性的动画或复杂控件中优先使用
通过这种机制,WPF实现了控件逻辑与视觉表现的解耦——开发者只需修改宿主控件的属性,模板外观即可自动响应
数据模板(DataTemplate)
定义与用途
- 作用:数据模板定义数据对象的呈现方式,将数据属性映射到UI元素。例如,将Customer对象的姓名和地址以特定布局显示。
- 应用场景:需自定义数据在控件中的显示形式(如在ListBox中显示复杂数据项)。
- 关键特性
DataType:指定模板适用的数据类型,支持隐式应用(无x:Key时自动匹配类型)。 - 绑定与布局:通过数据绑定({Binding})连接数据属性与UI元素,并定义布局结构(如StackPanel、Grid)
主要应用控件
ItemsControl及其派生控件
ListBox
为列表中的每个数据项定义布局,例如显示学生列表时自定义包含头像、姓名和分数的卡片布局
<ListBox ItemsSource="{Binding Students}"><ListBox.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal"><Image Source="{Binding Avatar}"/><TextBlock Text="{Binding Name}"/></StackPanel></DataTemplate></ListBox.ItemTemplate>
</ListBox>
ListView
类似ListBox,但支持更复杂的列定义。常用于数据表格展示,结合GridView定义列模板
<ListView><ListView.View><GridView><GridViewColumn Header="姓名" DisplayMemberBinding="{Binding Name}"/><GridViewColumn Header="年龄" CellTemplate="{StaticResource AgeTemplate}"/></GridView></ListView.View>
</ListView>
ComboBox
自定义下拉项的外观,例如在选项中加入图标和详细描述
<ComboBox ItemTemplate="{StaticResource PersonTemplate}"/>
ContentControl及其派生控件
Button、Label、Window
当控件内容为复杂对象时,用DataTemplate替代默认的ToString()显示。例如按钮内容显示为带图标的用户信息
<Button Content="{Binding SelectedUser}"><Button.ContentTemplate><DataTemplate><StackPanel><Image Source="{Binding Icon}"/><TextBlock Text="{Binding UserName}"/></StackPanel></DataTemplate></Button.ContentTemplate>
</Button>
TabItem
自定义标签页头的显示内容,如显示带状态指示器的标题
<TabControl><TabItem Header="{Binding TabHeader}"><TabItem.HeaderTemplate><DataTemplate><StackPanel><Ellipse Fill="{Binding StatusColor}" Width="10"/><TextBlock Text="{Binding Title}"/></StackPanel></DataTemplate></TabItem.HeaderTemplate></TabItem>
</TabControl>
其他特殊场景控件
TreeView
通过HierarchicalDataTemplate定义层级数据的显示,例如文件树结构
<TreeView ItemsSource="{Binding Folders}"><TreeView.ItemTemplate><HierarchicalDataTemplate ItemsSource="{Binding SubItems}"><TextBlock Text="{Binding Name}"/></HierarchicalDataTemplate></TreeView.ItemTemplate>
</TreeView>
DataGrid(需手动配置)
虽然DataGrid默认使用列绑定,但可通过CellTemplate自定义单元格内容。例如在单元格内显示评分星级
<DataGrid><DataGrid.Columns><DataGridTemplateColumn Header="评分"><DataGridTemplateColumn.CellTemplate><DataTemplate><RatingControl Value="{Binding Score}"/></DataTemplate></DataGridTemplateColumn.CellTemplate></DataGridTemplateColumn></DataGrid.Columns>
</DataGrid>
动态模板选择
核心方法
必须继承 DataTemplateSelector 类并重写 SelectTemplate 方法。该方法接收数据项和容器参数,返回匹配的 DataTemplate
- 设计多个 DataTemplate
在 XAML 资源中为不同数据类型定义模板。例如,文本项用 TextBlock,颜色项用 Border 背景
<Window.Resources><DataTemplate x:Key="TextTemplate"><TextBlock Text="{Binding Ob.Name}" /></DataTemplate><DataTemplate x:Key="ColorTemplate"><Border Background="{Binding Ob.Color}" Width="90" Height="30" /></DataTemplate>
</Window.Resources>
- 实现选择器类
自定义选择器将数据属性与模板关联。例如,根据 TypeName 属性选择模板
public class ListBoxTemplateSelector : DataTemplateSelector
{public DataTemplate TextTemplate { get; set; }public DataTemplate ColorTemplate { get; set; }public override DataTemplate SelectTemplate(object item, DependencyObject container){var data = item as DataModel;return data?.TypeName switch{"text" => TextTemplate,"color" => ColorTemplate,_ => base.SelectTemplate(item, container)};}
}
- 绑定到控件
将选择器实例赋给控件的 ItemTemplateSelector 属性
<ListBox ItemsSource="{Binding Items}"><ListBox.ItemTemplateSelector><local:ListBoxTemplateSelector TextTemplate="{StaticResource TextTemplate}"ColorTemplate="{StaticResource ColorTemplate}" /></ListBox.ItemTemplateSelector>
</ListBox>
典型应用场景