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

WPF MVVM下如何绑定DataGrid指定列符合条件的行数到TextBlock

WPF DataGrid 过滤后指定列条件计数实现方案

你之前写的Cnt属性不生效有三个核心问题:

  • 统计数据源错误:你遍历的是原始集合_penBills,没有经过PendingBills的Filter过滤,统计的不是DataGrid当前实际显示的行
  • 没有更新触发机制:你加了if (_cnt == 0)的判断,意味着只会在第一次访问属性时计算一次,后续账单增删、字段值修改、过滤条件变化时,既不会重新计算,也不会通知UI刷新值
  • 统计逻辑和过滤规则互斥:你给PendingBills设的过滤条件是PaidOn == "",但统计规则是PaidOn非空,就算计数逻辑正常执行,结果也永远是0,完全不符合预期。另外PaidOn本身是字符串类型的话,调用ToString()纯属多余,还可能在PaidOn为null时抛出空引用异常。

方案1:ViewModel 内实现(推荐,符合MVVM规范)

不需要使用值转换器,直接在ViewModel中做实时统计,可维护性更高,也不需要额外处理UI刷新问题,实现步骤如下:

  • 原始数据源改用ObservableCollection<Bills>,保证集合增删操作可被监听
  • 监听ICollectionView的CollectionChanged事件,在过滤、排序、行增删时触发计数刷新
  • 如果Bills类实现了INotifyPropertyChanged,额外监听单条账单的属性变更事件,行内字段修改时同步刷新计数
  • 计数变化时通过PropertyChanged事件通知UI更新

对应ViewModel代码示例:

public class BillsViewModel : INotifyPropertyChanged
{
    private readonly ObservableCollection<Bills> _penBills;
    public ICollectionView PendingBills { get; private set; }

    private int _specificConditionCount;
    /// <summary>
    /// 指定列符合条件的账单计数
    /// </summary>
    public int SpecificConditionCount
    {
        get => _specificConditionCount;
        private set
        {
            _specificConditionCount = value;
            OnPropertyChanged(nameof(SpecificConditionCount));
        }
    }

    public BillsViewModel()
    {
        // 初始化可观察集合
        _penBills = new ObservableCollection<Bills>(m.PBills);
        
        PendingBills = new ListCollectionView(_penBills)
        {
            Filter = o => ((Bills)o).PaidOn == ""
        };

        // 监听视图变更:过滤、排序、增删行时自动刷新计数
        PendingBills.CollectionChanged += (s, e) => RefreshConditionCount();
        
        // 监听单条数据的属性变更:字段值修改时自动刷新计数
        foreach (Bills bill in _penBills)
        {
            bill.PropertyChanged += (s, e) =>
            {
                // 监听你需要判断的字段,比如BillNo、PaidOn
                if (e.PropertyName == nameof(Bills.BillNo) || e.PropertyName == nameof(Bills.PaidOn))
                {
                    RefreshConditionCount();
                }
            };
        }

        // 初始化计算一次
        RefreshConditionCount();
    }

    /// <summary>
    /// 重新计算符合条件的行数
    /// </summary>
    private void RefreshConditionCount()
    {
        // 此处替换为你实际需要的判断规则
        // 示例为统计BillNo非空的行数,其他判断示例:
        // 值为指定文本:x.BillNo == "目标文本"
        // 值为null:x.BillNo == null
        SpecificConditionCount = PendingBills.Cast<Bills>()
            .Count(x => !string.IsNullOrEmpty(x.BillNo));
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    }
}

前端XAML直接绑定对应属性即可:

<TextBlock Text="{Binding SpecificConditionCount, StringFormat='符合条件账单数: {0}'}"/>

方案2:使用IValueConverter实现(适合规则复用场景)

如果统计规则需要在多个页面复用,不想在每个ViewModel里重复写计数逻辑,可以实现值转换器:
首先编写转换器类:

public class SpecificBillCountConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is not ICollectionView view) return 0;
        // 此处替换为你实际需要的判断规则,也可以通过parameter传入条件参数做灵活适配
        return view.Cast<Bills>().Count(x => !string.IsNullOrEmpty(x.BillNo));
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

在XAML中注册转换器后使用:

<!-- 窗口/用户控件资源节点注册转换器 -->
<Window.Resources>
    <local:SpecificBillCountConverter x:Key="SpecificBillCountConv"/>
</Window.Resources>

<!-- 绑定传入ICollectionView,通过转换器输出计数 -->
<TextBlock Text="{Binding PendingBills, Converter={StaticResource SpecificBillCountConv}, StringFormat='符合条件账单数: {0}'}"/>

注意:该方案有个缺陷:ICollectionView触发CollectionChanged时,绑定源的引用本身没有变化,默认不会触发转换器重新执行,需要额外处理绑定刷新逻辑,稳定性不如ViewModel内实现的方案。


内容的提问来源于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.27 04:57:24