WPF DataGrid中IsEditable=True的ComboBox切换时SelectedItem不触发问题
问题根因
该问题是WPF DataGrid的默认路由事件处理逻辑导致:当你点击另一行的可编辑ComboBox时,焦点直接被ComboBox控件捕获,路由事件被控件自身处理后没有冒泡到DataGrid层,因此DataGrid不会触发默认的行选择逻辑,SelectedItem绑定也不会更新。只有点击行内非编辑控件的空白区域时,事件才会冒泡到DataGrid触发行选择。
解决方案
方案1:轻量视图层修复(无业务逻辑,不违反MVVM)
该方案只需要在视图层添加少量代码,适配所有行内编辑控件的场景:
- 给DataGrid添加行样式,绑定键盘焦点获取事件:
<DataGrid x:Name="dataGrid" ItemsSource="{Binding DisplayedRows}" SelectedItem="{Binding SelectedRow}" SelectionUnit="FullRow"> <DataGrid.Resources> <Style TargetType="DataGridRow"> <EventSetter Event="PreviewGotKeyboardFocus" Handler="DataGridRow_PreviewGotKeyboardFocus"/> </Style> </DataGrid.Resources> <!-- 原有列定义 --> </DataGrid>
- 在对应.xaml.cs的后台文件中添加事件处理逻辑:
private void DataGridRow_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { if (sender is DataGridRow row && !row.IsSelected) { // 可选:提交上一行的编辑内容,避免修改丢失 dataGrid.CommitEdit(DataGridEditingUnit.Row, true); row.IsSelected = true; } }
该逻辑仅处理视图层面的行选中状态同步,不涉及业务逻辑,不属于MVVM模式的违规用法。
方案2:纯XAML MVVM实现(无后台代码)
如果要求完全避免后台代码,可以用附加行为封装上述逻辑,直接在XAML中调用:
- 首先创建通用的附加行为类:
public static class DataGridRowAutoSelectBehavior { public static readonly DependencyProperty EnableProperty = DependencyProperty.RegisterAttached( "Enable", typeof(bool), typeof(DataGridRowAutoSelectBehavior), new PropertyMetadata(false, OnEnableChanged)); public static void SetEnable(DependencyObject element, bool value) { element.SetValue(EnableProperty, value); } public static bool GetEnable(DependencyObject element) { return (bool)element.GetValue(EnableProperty); } private static void OnEnableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not DataGridRow row) return; if ((bool)e.NewValue) { row.PreviewGotKeyboardFocus += OnRowPreviewGotKeyboardFocus; } else { row.PreviewGotKeyboardFocus -= OnRowPreviewGotKeyboardFocus; } } private static void OnRowPreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { if (sender is DataGridRow row && !row.IsSelected) { if (ItemsControl.ItemsControlFromItemContainer(row) is DataGrid grid) { grid.CommitEdit(DataGridEditingUnit.Row, true); } row.IsSelected = true; } } }
- 在XAML的DataGrid行样式中启用该行为即可:
<DataGrid.Resources> <Style TargetType="DataGridRow"> <Setter Property="local:DataGridRowAutoSelectBehavior.Enable" Value="True"/> </Style> </DataGrid.Resources>
修改完成后,只要行内任意控件获得焦点,都会自动触发当前行选中,SelectedRow的setter会正常执行。
内容的提问来源于stack exchange,提问作者Istvan Heckl
相关产品推荐
相关产品推荐

