如何在WPF DataGrid中复用列定义,避免重复实现高尔夫成绩列
复用WPF DataGrid球洞列的两种实用方案
当然可以复用列定义,不用重复写18遍DataGridTemplateColumn。下面给出两种落地性强的实现方式:
方案一:后台代码动态生成列(最直接高效)
如果你的DataGrid绑定的球员对象包含HoleScores集合(比如List<int>或ObservableCollection<int>),可以通过循环批量创建列,统一复用模板逻辑:
// 定义通用的单元格显示模板 var cellTemplate = new DataTemplate(); var textBlockFactory = new FrameworkElementFactory(typeof(TextBlock)); cellTemplate.VisualTree = textBlockFactory; // 定义通用的单元格编辑模板 var editingTemplate = new DataTemplate(); var textBoxFactory = new FrameworkElementFactory(typeof(TextBox)); textBoxFactory.SetValue(TextBox.BorderThicknessProperty, new Thickness(0)); editingTemplate.VisualTree = textBoxFactory; // 循环生成18个球洞列 for (int holeIndex = 0; holeIndex < 18; holeIndex++) { var column = new DataGridTemplateColumn { Header = $"第{holeIndex + 1}洞", CellTemplate = cellTemplate, CellEditingTemplate = editingTemplate }; // 绑定对应索引的HoleScores值 var displayBinding = new Binding($"HoleScores[{holeIndex}]"); textBlockFactory.SetBinding(TextBlock.TextProperty, displayBinding); var editBinding = new Binding($"HoleScores[{holeIndex}]") { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }; textBoxFactory.SetBinding(TextBox.TextProperty, editBinding); MyDataGrid.Columns.Add(column); }
注意:如果HoleScores是ObservableCollection,绑定会自动响应集合变更;若为普通List,需手动触发属性变更通知。
方案二:XAML资源+附加属性(纯声明式实现)
- 先创建一个附加属性类,用来传递球洞索引:
public static class HoleColumnHelper { public static readonly DependencyProperty HoleIndexProperty = DependencyProperty.RegisterAttached("HoleIndex", typeof(int), typeof(HoleColumnHelper), new PropertyMetadata(0, OnHoleIndexChanged)); public static int GetHoleIndex(DependencyObject obj) { return (int)obj.GetValue(HoleIndexProperty); } public static void SetHoleIndex(DependencyObject obj, int value) { obj.SetValue(HoleIndexProperty, value); } private static void OnHoleIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is DataGridTemplateColumn column) { // 更新显示模板的绑定 if (column.CellTemplate.LoadContent() is TextBlock tb) { tb.SetBinding(TextBlock.TextProperty, new Binding($"HoleScores[{(int)e.NewValue}]")); } // 更新编辑模板的绑定 if (column.CellEditingTemplate.LoadContent() is TextBox tbEdit) { tbEdit.SetBinding(TextBox.TextProperty, new Binding($"HoleScores[{(int)e.NewValue}]") { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); } } } }
- 在XAML中定义通用模板资源,然后引用并指定球洞索引:
<Window.Resources> <DataTemplate x:Key="HoleCellTemplate"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"/> </DataTemplate> <DataTemplate x:Key="HoleCellEditingTemplate"> <TextBox HorizontalAlignment="Center" VerticalAlignment="Center"/> </DataTemplate> </Window.Resources> <DataGrid x:Name="MyDataGrid" AutoGenerateColumns="False"> <!-- 总杆、净杆列 --> <DataGridTextColumn Header="总杆" Binding="{Binding Gross}" Width="80"/> <DataGridTextColumn Header="净杆" Binding="{Binding NetOrPoints}" Width="80"/> <!-- 复用球洞列,仅需修改Header和HoleIndex --> <DataGridTemplateColumn Header="第1洞" local:HoleColumnHelper.HoleIndex="0" CellTemplate="{StaticResource HoleCellTemplate}" CellEditingTemplate="{StaticResource HoleCellEditingTemplate}"/> <DataGridTemplateColumn Header="第2洞" local:HoleColumnHelper.HoleIndex="1" CellTemplate="{StaticResource HoleCellTemplate}" CellEditingTemplate="{StaticResource HoleCellEditingTemplate}"/> <!-- ... 依次添加到第18洞 --> </DataGrid>
两种方案都能彻底避免重复编写列模板,方案一适合代码驱动的场景,方案二更贴合XAML声明式开发的习惯,可根据项目需求选择。
内容的提问来源于stack exchange,提问作者MikeP
相关产品推荐
相关产品推荐

