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

WPF DataGrid中IsEditable=True的ComboBox切换时SelectedItem不触发问题

问题根因

该问题是WPF DataGrid的默认路由事件处理逻辑导致:当你点击另一行的可编辑ComboBox时,焦点直接被ComboBox控件捕获,路由事件被控件自身处理后没有冒泡到DataGrid层,因此DataGrid不会触发默认的行选择逻辑,SelectedItem绑定也不会更新。只有点击行内非编辑控件的空白区域时,事件才会冒泡到DataGrid触发行选择。

解决方案

方案1:轻量视图层修复(无业务逻辑,不违反MVVM)

该方案只需要在视图层添加少量代码,适配所有行内编辑控件的场景:

  1. 给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>
  1. 在对应.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中调用:

  1. 首先创建通用的附加行为类:
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;
        }
    }
}
  1. 在XAML的DataGrid行样式中启用该行为即可:
<DataGrid.Resources>
    <Style TargetType="DataGridRow">
        <Setter Property="local:DataGridRowAutoSelectBehavior.Enable" Value="True"/>
    </Style>
</DataGrid.Resources>

修改完成后,只要行内任意控件获得焦点,都会自动触发当前行选中,SelectedRow的setter会正常执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 04:54:03