WPF DataGridColumn绑定IsReadOnly时DataContext为null问题
问题原因
DataGridColumn 及其派生类(包括DataGridTextColumn、第三方的DataGridComboBoxColumn)的实例不属于WPF可视化树范畴,不会沿着控件树继承父级DataGrid的DataContext,因此直接在列属性上写{Binding IsLocked}找不到绑定源,会因为源为null失效。
你代码里两类绑定正常工作的逻辑非常明确:
- 列的
Binding属性(比如{Binding Name}、SelectedValueBinding这类)是列给生成的单元格/编辑控件传递的专用绑定配置,单元格加载时会自动将当前行的数据项作为绑定源,不需要列本身拿到DataContext CellTemplate内的控件属于单元格可视化树的一部分,加载时DataContext就是当前行对应的数据项,因此{Binding IsLocked}可以正常取值
解决方案
根据IsLocked是全局ViewModel属性还是行级数据属性,选择对应方案即可:
方案1:全局统一控制列只读(所有行状态一致)
利用Freezable类可跨可视化树传递DataContext的特性,实现轻量绑定代理:
- 先在项目中添加代理类:
public class BindingProxy : Freezable { protected override Freezable CreateInstanceCore() => new BindingProxy(); public object Data { get => GetValue(DataProperty); set => SetValue(DataProperty, value); } public static readonly DependencyProperty DataProperty = DependencyProperty.Register(nameof(Data), typeof(object), typeof(BindingProxy), new PropertyMetadata(null)); }
- 在DataGrid所在的页面/窗口资源中声明代理实例,绑定到当前全局DataContext:
<UserControl.Resources> <local:BindingProxy x:Key="GridDataContextProxy" Data="{Binding}" /> </UserControl.Resources>
- 修改列上的IsReadOnly绑定,指定源为代理资源:
<DataGridTextColumn x:Name="NameColumn" Header="Name" Binding="{Binding Name, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding Data.IsLocked, Source={StaticResource GridDataContextProxy}}" /> <materialDesign:DataGridComboBoxColumn Header="Produktart" IsReadOnly="{Binding Data.IsLocked, Source={StaticResource GridDataContextProxy}, UpdateSourceTrigger=PropertyChanged}" IsEditable="True" Width="100" SelectedValueBinding="{Binding ProductType, UpdateSourceTrigger=PropertyChanged}" ItemsSourceBinding="{Binding ProducerTypesValues, UpdateSourceTrigger=PropertyChanged }" />
方案2:行级控制只读(不同行根据自身IsLocked单独控制是否可编辑)
从你代码中IsLocked用于控制锁图标显示的逻辑判断,该场景更符合你的需求,最稳妥无额外依赖的方式是通过BeginningEdit事件拦截:
- 给DataGrid挂载事件,删掉列上原本失效的
IsReadOnly="{Binding IsLocked}"配置:
<DataGrid BeginningEdit="DataGrid_OnBeginningEdit" 其余属性保持原有配置即可> <!-- 原有列代码 --> </DataGrid>
- 在后台代码编写事件逻辑,判断当前行数据的IsLocked状态,锁定行直接取消编辑:
private void DataGrid_OnBeginningEdit(object sender, DataGridBeginningEditEventArgs e) { if (e.Row.Item is 你的行数据实际类型 item && item.IsLocked) { e.Cancel = true; } }
该方案对所有类型的列都生效,不需要额外编写代理类,也不需要逐列修改绑定配置。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

