You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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值?


解决方案

当前代码的核心问题有两个:

  1. 把数据项绑定设置到了列本身的ValueProperty,但列是DataGrid的全局元素,并非每行数据项的容器,无法对应到单个数据项的值。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 04:31:01