自定义DataGridBoolColumn绑定值始终为False,如何重定向Binding至自定义依赖属性?
问题描述
尝试创建自定义DataGridBoolColumn,根据绑定值显示勾选/叉号图标,但绑定值始终为False,列中一直显示叉号,无XAML绑定错误。
自定义列代码:
public class DataGridBoolColumn : DataGridBoundColumn { private const double DATAGRIDBOOLCOLUMN_leftMargin = 12.0; private const double DATAGRIDBOOLCOLUMN_rightMargin = 12.0; public bool Value { get { return (bool)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } // Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc... public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(bool), typeof(DataGridBoolColumn), new PropertyMetadata(false)); private FrameworkElement CreateIcon() { // Set Binding to ValueProperty BindingOperations.SetBinding(this, ValueProperty, Binding); PackIconMaterial icon = new PackIconMaterial(); icon.Margin = new Thickness(DATAGRIDBOOLCOLUMN_leftMargin, 0.0, DATAGRIDBOOLCOLUMN_rightMargin, 0.0); icon.Height = 14.0; // Determine if the icon should show Check or Cross based on Value if (Value) { icon.Foreground = new SolidColorBrush(new Color() { A = 255, R = 22, G = 100, B = 44 }); icon.Kind = PackIconMaterialKind.Check; } else { icon.Foreground = new SolidColorBrush(new Color() { A = 255, R = 128, G = 16, B = 42 }); icon.Kind = PackIconMaterialKind.Close; } return icon; } protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) { return CreateIcon(); } protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) { return CreateIcon(); } }
XAML绑定代码:
<DataGrid ItemsSource="{Binding Path=FilteredItems}"> <local:DataGridBoolColumn Header="Trackable" Binding="{Binding Path=IsTrackable}" /> </DataGrid>
核心疑问:如何将Binding正确重定向到自定义依赖属性,让Value能获取到数据项的IsTrackable值?
解决方案
当前代码的核心问题有两个:
- 把数据项绑定设置到了列本身的
ValueProperty,但列是DataGrid的全局元素,并非每行数据项的容器,无法对应到单个数据项的值。 CreateIcon中直接读取Value是同步操作,而绑定是异步生效的,此时绑定还未完成,因此始终取到默认值False。
以下是两种可行的修改方案:
方案一:使用绑定+转换器直接控制图标
无需自定义列的Value依赖属性,直接将数据项的IsTrackable绑定到图标的Kind和Foreground属性,通过转换器实现逻辑转换:
1. 创建两个转换器
// 布尔值转图标类型转换器 public class BoolToIconKindConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return value is bool b && b ? PackIconMaterialKind.Check : PackIconMaterialKind.Close; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } // 布尔值转前景色转换器 public class BoolToForegroundConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is bool b && b) return new SolidColorBrush(Color.FromArgb(255, 22, 100, 44)); return new SolidColorBrush(Color.FromArgb(255, 128, 16, 42)); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
2. 修改自定义列代码
public class DataGridBoolColumn : DataGridBoundColumn { private const double DATAGRIDBOOLCOLUMN_leftMargin = 12.0; private const double DATAGRIDBOOLCOLUMN_rightMargin = 12.0; private static readonly BoolToIconKindConverter _iconConverter = new BoolToIconKindConverter(); private static readonly BoolToForegroundConverter _foregroundConverter = new BoolToForegroundConverter(); protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) { var icon = new PackIconMaterial { Margin = new Thickness(DATAGRIDBOOLCOLUMN_leftMargin, 0, DATAGRIDBOOLCOLUMN_rightMargin, 0), Height = 14.0 }; // 绑定图标类型 BindingOperations.SetBinding(icon, PackIconMaterial.KindProperty, new Binding { Path = Binding.Path, Source = dataItem, Converter = _iconConverter }); // 绑定前景色 BindingOperations.SetBinding(icon, PackIconMaterial.ForegroundProperty, new Binding { Path = Binding.Path, Source = dataItem, Converter = _foregroundConverter }); return icon; } protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) { // 编辑模式可复用图标,或替换为CheckBox等编辑控件 return GenerateElement(cell, dataItem); } }
方案二:使用附加属性+属性变更回调
通过附加属性监听数据项值的变化,动态更新图标状态,更贴合DataGridColumn的设计逻辑:
public class DataGridBoolColumn : DataGridBoundColumn { private const double DATAGRIDBOOLCOLUMN_leftMargin = 12.0; private const double DATAGRIDBOOLCOLUMN_rightMargin = 12.0; // 定义附加属性用于绑定数据项值 public static readonly DependencyProperty BoolValueProperty = DependencyProperty.RegisterAttached( "BoolValue", typeof(bool), typeof(DataGridBoolColumn), new PropertyMetadata(false, OnBoolValueChanged)); // 属性变更时更新图标 private static void OnBoolValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not PackIconMaterial icon || e.NewValue is not bool value) return; if (value) { icon.Foreground = new SolidColorBrush(Color.FromArgb(255, 22, 100, 44)); icon.Kind = PackIconMaterialKind.Check; } else { icon.Foreground = new SolidColorBrush(Color.FromArgb(255, 128, 16, 42)); icon.Kind = PackIconMaterialKind.Close; } } protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) { var icon = new PackIconMaterial { Margin = new Thickness(DATAGRIDBOOLCOLUMN_leftMargin, 0, DATAGRIDBOOLCOLUMN_rightMargin, 0), Height = 14.0 }; // 使用DataGridBoundColumn的BindCellContent方法绑定附加属性 BindCellContent(icon, BoolValueProperty); return icon; } protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) { return GenerateElement(cell, dataItem); } }
关键错误总结
- 不要将数据项绑定设置到列实例的依赖属性上,列是全局对象,无法对应到每行的具体数据项。
- 绑定是异步生效的,不能在控件创建阶段直接读取绑定属性值,需通过转换器、属性变更回调等方式响应值变化。
内容的提问来源于stack exchange,提问作者craig1231
相关产品推荐
相关产品推荐

