C# WPF:如何将重复DataGrid列样式转为资源并单次绑定对象?
解决方案:复用DataGrid列样式,消除重复代码
核心思路:通过BindingProxy传递列索引,让通用样式动态绑定对应Aps对象
WPF的DataGridCell上下文是行数据,无法直接获取列索引,因此需要借助**绑定代理(BindingProxy)**传递列的索引信息,让通用样式能根据索引动态绑定Aps集合里的对应项。
步骤1:实现BindingProxy类
这个类用于在资源中传递绑定值(此处为列索引):
public class BindingProxy : Freezable { protected override Freezable CreateInstanceCore() { return new BindingProxy(); } public object Data { get => GetValue(DataProperty); set => SetValue(DataProperty, value); } public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null)); }
步骤2:定义通用样式资源
在Resources中统一编写单元格样式和文本块样式,通过BindingProxy动态获取列索引:
<Window.Resources> <!-- 通用单元格样式 --> <Style x:Key="GenericDataGridCellStyle" TargetType="DataGridCell" BasedOn="{StaticResource dgc}"> <Setter Property="ToolTip" Value="{Binding Aps[{Binding Data, Source={StaticResource ColumnIndexProxy}}].ToolTipText}" /> <Setter Property="ContextMenu" Value="{StaticResource contextMenu}" /> <Setter Property="Background" Value="{Binding Aps[{Binding Data, Source={StaticResource ColumnIndexProxy}}].CellBackground}" /> <Setter Property="Foreground" Value="{Binding Aps[{Binding Data, Source={StaticResource ColumnIndexProxy}}].CellForeground}" /> <Setter Property="BorderBrush" Value="{Binding Aps[{Binding Data, Source={StaticResource ColumnIndexProxy}}].CellBorderBrush}" /> <Setter Property="BorderThickness" Value="{Binding Aps[{Binding Data, Source={StaticResource ColumnIndexProxy}}].CellBorderThickness}" /> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="Background" Value="{Binding Aps[{Binding Data, Source={StaticResource ColumnIndexProxy}}].CellBackground}" /> <Setter Property="Foreground" Value="{Binding Aps[{Binding Data, Source={StaticResource ColumnIndexProxy}}].CellForeground}" /> </Trigger> </Style.Triggers> </Style> <!-- 通用文本块样式 --> <Style x:Key="GenericTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource tb}" /> </Window.Resources>
步骤3:简化DataGrid列定义
每个列只需指定索引、Header和绑定,直接引用通用样式即可:
<materialDesign:DataGridTextColumn x:Name="Jan" Header="Jan" Binding="{Binding Aps[0].CellValue}"> <materialDesign:DataGridTextColumn.Resources> <!-- 当前列专属的索引代理 --> <local:BindingProxy x:Key="ColumnIndexProxy" Data="0"/> </materialDesign:DataGridTextColumn.Resources> <DataGridTextColumn.CellStyle> <StaticResource ResourceKey="GenericDataGridCellStyle"/> </DataGridTextColumn.CellStyle> <DataGridTextColumn.ElementStyle> <StaticResource ResourceKey="GenericTextBlockStyle"/> </DataGridTextColumn.ElementStyle> </materialDesign:DataGridTextColumn> <materialDesign:DataGridTextColumn x:Name="Feb" Header="Feb" Binding="{Binding Aps[1].CellValue}"> <materialDesign:DataGridTextColumn.Resources> <local:BindingProxy x:Key="ColumnIndexProxy" Data="1"/> </materialDesign:DataGridTextColumn.Resources> <DataGridTextColumn.CellStyle> <StaticResource ResourceKey="GenericDataGridCellStyle"/> </DataGridTextColumn.CellStyle> <DataGridTextColumn.ElementStyle> <StaticResource ResourceKey="GenericTextBlockStyle"/> </DataGridTextColumn.ElementStyle> </materialDesign:DataGridTextColumn> <!-- 剩余10列依此类推,仅修改索引、Name和Header -->
可选优化:改用DataGridTemplateColumn
如果允许替换列类型,可以把单元格内容也封装到通用模板中,进一步简化代码:
<Window.Resources> <!-- 通用单元格内容模板 --> <DataTemplate x:Key="GenericCellTemplate"> <TextBlock Text="{Binding Aps[{Binding Data, Source={StaticResource ColumnIndexProxy}}].CellValue}" Style="{StaticResource tb}"/> </DataTemplate> </Window.Resources> <!-- 列定义示例 --> <materialDesign:DataGridTemplateColumn x:Name="Jan" Header="Jan"> <materialDesign:DataGridTemplateColumn.Resources> <local:BindingProxy x:Key="ColumnIndexProxy" Data="0"/> </materialDesign:DataGridTemplateColumn.Resources> <DataGridTemplateColumn.CellStyle> <StaticResource ResourceKey="GenericDataGridCellStyle"/> </DataGridTemplateColumn.CellStyle> <DataGridTemplateColumn.CellTemplate> <StaticResource ResourceKey="GenericCellTemplate"/> </DataGridTemplateColumn.CellTemplate> </materialDesign:DataGridTemplateColumn>
关键说明
- 绑定代理的作用是突破WPF绑定上下文限制,让单元格样式能获取到列的索引值;
- 每个列的
Resources中定义独立的ColumnIndexProxy,确保样式绑定对应索引的Aps对象; - 所有重复的样式逻辑集中到通用资源中,后续修改只需维护一处即可。
内容的提问来源于stack exchange,提问作者Kariko
相关产品推荐
相关产品推荐

