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

DataGrid列IsReadOnly属性按行绑定失败,如何解决?

解决DataGrid列单元格动态只读的绑定问题

首先咱们先搞清楚核心矛盾:为什么你的Binding能正常工作,但IsReadOnly绑定失败?

DataGrid的内置列(比如DataGridCheckBoxColumn)不属于可视化树的一部分,它们的默认DataContext是ViewModel(也就是DataGrid的DataContext),而非每行的数据项MyItem。但列的Binding属性是特殊设计的——它不会直接绑定到列的DataContext,而是会自动将这个绑定应用到每个单元格内的控件上,而每个单元格的DataContext恰好是当前行的MyItem,所以Binding="{Binding MyProp.MyValue}"能正常找到属性。

而IsReadOnly是列本身的属性,它的绑定上下文是列的DataContext(ViewModel),所以你尝试的两种方式都走不通:

  • IsReadOnly="{Binding MyProp.IsReadOnly, Source={StaticResource proxy}}":proxy的Data是ViewModel,会去ViewModel里找MyProp,但MyProp是MyItem的属性,自然找不到。
  • IsReadOnly="{Binding Data.MyProp.IsReadOnly, Source={StaticResource proxy}}":同样是找ViewModel的Data.MyProp,还是不对。

解决方案1:使用DataGridTemplateColumn(最直观)

改用DataGridTemplateColumn,你可以直接在单元格模板里定义控件,并绑定到行数据的属性。因为模板里的控件属于可视化树,能继承行的DataContext:

<DataGridTemplateColumn Header="MyProp"
                        Visibility="{Binding Data.AnotherProp, Source={StaticResource proxy}, Converter={StaticResource BoolToVisibilityConverter}}">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <!-- CheckBox没有IsReadOnly属性,用IsEnabled配合反转转换器实现只读效果 -->
            <CheckBox IsChecked="{Binding MyProp.MyValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                      IsEnabled="{Binding MyProp.IsReadOnly, Converter={StaticResource InverseBooleanConverter}}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

这里需要一个反转布尔值的转换器(把IsReadOnly=true转成IsEnabled=false),转换器代码示例:

public class InverseBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value is bool b ? !b : value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value is bool b ? !b : value;
    }
}

如果是TextBox这类自带IsReadOnly属性的控件,直接绑定即可:

<TextBox Text="{Binding MyProp.MyValue}" IsReadOnly="{Binding MyProp.IsReadOnly}" />

解决方案2:使用附加属性(保留内置列)

如果你想继续使用DataGridCheckBoxColumn,可以通过附加属性把IsReadOnly的绑定传递到每个单元格上(单元格属于可视化树,能访问行DataContext):

首先定义附加属性:

public static class DataGridCellHelper
{
    public static readonly DependencyProperty CellIsReadOnlyBindingProperty =
        DependencyProperty.RegisterAttached(
            "CellIsReadOnlyBinding",
            typeof(Binding),
            typeof(DataGridCellHelper),
            new PropertyMetadata(null, OnCellIsReadOnlyBindingChanged));

    public static Binding GetCellIsReadOnlyBinding(DependencyObject obj)
    {
        return (Binding)obj.GetValue(CellIsReadOnlyBindingProperty);
    }

    public static void SetCellIsReadOnlyBinding(DependencyObject obj, Binding value)
    {
        obj.SetValue(CellIsReadOnlyBindingProperty, value);
    }

    private static void OnCellIsReadOnlyBindingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is DataGridColumn column && e.NewValue is Binding binding)
        {
            // 为列的单元格设置样式,把绑定应用到DataGridCell的IsReadOnly属性
            column.CellStyle = new Style(typeof(DataGridCell))
            {
                Setters = { new Setter(DataGridCell.IsReadOnlyProperty, binding) }
            };
        }
    }
}

然后在XAML中使用:

<DataGridCheckBoxColumn Header="MyProp"
                        local:DataGridCellHelper.CellIsReadOnlyBinding="{Binding MyProp.IsReadOnly}"
                        Binding="{Binding MyProp.MyValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        Visibility="{Binding Data.AnotherProp, Source={StaticResource proxy}, Converter={StaticResource BoolToVisibilityConverter}}" />

这样每个单元格的IsReadOnly属性会绑定到当前行MyItem的MyProp.IsReadOnly,就能实现按行动态只读了。

内容的提问来源于stack exchange,提问作者Gerard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 12:54:05