MVVM重构时DataGridComboBox绑定外部ItemsSource失败的求助
问题原因
DataGridComboBoxColumn 不属于界面的视觉树结构,因此它的DataContext不会自动继承自DataGrid的DataContext。当你直接写{Binding Categories}时,绑定引擎会尝试在当前行的数据对象(即Product实例)中寻找Categories属性,而非ViewModel中的集合,这就是绑定失效的核心原因。
可行解决方案
方案1:改用DataGridTemplateColumn嵌套ComboBox
这是最常用的解决方式,模板内的ComboBox属于视觉树,可通过RelativeSource正常向上找到父级DataGrid的DataContext:
<DataGrid x:Name="dataGrid" ItemsSource="{Binding Products}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding Index}" IsReadOnly="True" Header="Index" SortDirection="Ascending"/> <DataGridTextColumn Binding="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Width="Auto" Header="Name"/> <!-- 替换原DataGridComboBoxColumn为TemplateColumn --> <DataGridTemplateColumn Header="Type"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ComboBox ItemsSource="{Binding DataContext.Categories, RelativeSource={RelativeSource AncestorType=DataGrid}}" DisplayMemberPath="Name" SelectedValuePath="ID" SelectedValue="{Binding CategoryID, UpdateSourceTrigger=PropertyChanged}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <!-- 可选:单独定义编辑状态模板 --> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <ComboBox ItemsSource="{Binding DataContext.Categories, RelativeSource={RelativeSource AncestorType=DataGrid}}" DisplayMemberPath="Name" SelectedValuePath="ID" SelectedValue="{Binding CategoryID, UpdateSourceTrigger=PropertyChanged}" IsDropDownOpen="True"/> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
方案2:使用BindingProxy代理类
创建轻量级代理类,帮助DataGridComboBoxColumn间接访问ViewModel的DataContext:
- 定义代理类:
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(nameof(Data), typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null)); }
- 在XAML资源中声明代理并绑定到ViewModel:
<Window.Resources> <local:BindingProxy x:Key="ViewModelProxy" Data="{Binding}"/> </Window.Resources>
- 修改
DataGridComboBoxColumn的绑定:
<DataGridComboBoxColumn ItemsSource="{Binding Data.Categories, Source={StaticResource ViewModelProxy}}" Header="Type" DisplayMemberPath="Name" SelectedValuePath="ID" SelectedValueBinding="{Binding CategoryID, UpdateSourceTrigger=PropertyChanged}"/>
方案3:直接引用ViewModel作为静态资源
如果ViewModel在XAML中已声明为静态资源(例如<local:YourViewModel x:Key="MainVM"/>),可直接绑定该资源:
<DataGridComboBoxColumn ItemsSource="{Binding Categories, Source={StaticResource MainVM}}" Header="Type" DisplayMemberPath="Name" SelectedValuePath="ID" SelectedValueBinding="{Binding CategoryID, UpdateSourceTrigger=PropertyChanged}"/>
内容的提问来源于stack exchange,提问作者atLeastTried
相关产品推荐
相关产品推荐

