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

如何在WPF MVVM模式下正确获取DataGrid选中行数?

问题原因

你用SelectedItem绑定SelItm,但SelectedItem仅对应单个选中项,在Extended多选模式下根本无法获取所有选中行,所以调用SelItm.Count()自然会出错。

符合MVVM的正确实现方式

WPF的DataGrid.SelectedItems是只读集合,不能直接绑定到ViewModel,需要通过自定义附加属性实现选中项集合与ViewModel属性的双向同步,下面是具体实现步骤:

步骤1:创建自定义附加属性类

新建静态类,封装选中项同步逻辑:

using System.Collections;
using System.Windows;
using System.Windows.Controls;

public static class DataGridSelectedItemsBehavior
{
    public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.RegisterAttached(
            "SelectedItems",
            typeof(IList),
            typeof(DataGridSelectedItemsBehavior),
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemsChanged));

    public static IList GetSelectedItems(DependencyObject obj)
    {
        return (IList)obj.GetValue(SelectedItemsProperty);
    }

    public static void SetSelectedItems(DependencyObject obj, IList value)
    {
        obj.SetValue(SelectedItemsProperty, value);
    }

    private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is DataGrid dataGrid)
        {
            dataGrid.SelectionChanged -= DataGrid_SelectionChanged;
            if (e.NewValue is IList newSelectedItems)
            {
                dataGrid.SelectionChanged += DataGrid_SelectionChanged;
                // 同步初始选中项
                dataGrid.SelectedItems.Clear();
                foreach (var item in newSelectedItems)
                {
                    dataGrid.SelectedItems.Add(item);
                }
            }
        }
    }

    private static void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (sender is DataGrid dataGrid)
        {
            var selectedItems = GetSelectedItems(dataGrid);
            if (selectedItems == null) return;

            // 移除取消选中的项
            foreach (var item in e.RemovedItems)
            {
                if (selectedItems.Contains(item))
                {
                    selectedItems.Remove(item);
                }
            }
            // 添加新选中的项
            foreach (var item in e.AddedItems)
            {
                if (!selectedItems.Contains(item))
                {
                    selectedItems.Add(item);
                }
            }
        }
    }
}

步骤2:修改ViewModel代码

添加选中项集合属性和选中行数字段,确保ViewModel实现INotifyPropertyChanged接口:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

public class YourViewModel : INotifyPropertyChanged
{
    private ICollectionView _allFilteredStudents;
    public ICollectionView FilteredStudents
    {
        get
        {
            if(_allFilteredStudents == null)
            {
                this._allFilteredStudents = new ListCollectionView(GetAllStudents())
                {
                    Filter = o => ((Students)o).Name != "Ram"
                };
            }
            return _allFilteredStudents;
        }
    }

    private ObservableCollection<Students> _selectedStudents;
    public ObservableCollection<Students> SelectedStudents
    {
        get => _selectedStudents;
        set
        {
            _selectedStudents = value;
            OnPropertyChanged();
            SelectedRowCount = _selectedStudents.Count;
        }
    }

    private int _selectedRowCount;
    public int SelectedRowCount
    {
        get => _selectedRowCount;
        set
        {
            _selectedRowCount = value;
            OnPropertyChanged();
        }
    }

    public YourViewModel()
    {
        SelectedStudents = new ObservableCollection<Students>();
    }

    // 模拟获取学生数据方法
    private List<Students> GetAllStudents()
    {
        return new List<Students>();
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

// 学生实体类示例
public class Students
{
    public string Name { get; set; }
    public string Address { get; set; }
    public int Age { get; set; }
}

步骤3:修改DataGrid的XAML代码

移除原有SelectedItem绑定,添加自定义附加属性绑定:

<Window x:Class="YourNamespace.YourWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:YourNamespace">
    <Grid>
        <DataGrid
            ItemsSource="{Binding FilteredStudents}"
            SelectionMode="Extended"
            AutoGenerateColumns="False"
            IsReadOnly="True"
            SelectionUnit="FullRow"
            HeadersVisibility="Column"
            local:DataGridSelectedItemsBehavior.SelectedItems="{Binding SelectedStudents, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
            <DataGrid.Columns>
                <DataGridTextColumn
                    Header="Bill No."
                    Binding="{Binding Path=Name, Mode=OneWay}"
                    Width="260"
                    IsReadOnly="True" />
                <DataGridTextColumn
                    Header="Bill Date"
                    Binding="{Binding Path=Address, Mode=OneWay}"
                    Width="200"
                    IsReadOnly="True" />
                <DataGridTextColumn
                    Header="Amount"
                    Binding="{Binding Path=Age, Mode=OneWay}"
                    Width="210"
                    IsReadOnly="True" />
            </DataGrid.Columns>
        </DataGrid>

        <!-- 绑定选中行数的标签 -->
        <Label Content="{Binding SelectedRowCount}" Margin="10,0"/>
    </Grid>
</Window>
原理说明

自定义附加属性通过监听DataGrid.SelectionChanged事件,将界面选中项同步到ViewModel的SelectedStudents集合,同时支持从ViewModel反向设置选中项。此后你可以通过SelectedStudents.Count准确获取选中行数,完全符合MVVM模式的解耦要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 20:55:50