当前位置: 首页 > news >正文

BindingList的应用与改进

在编写UI的过程中,我们通常使用ObservableCollection来监听列表的变化。然而,ObservableCollection只能在添加/移动/移除元素时通知界面,这意味着元素内部更改时,ObservableCollection是无法通知的

如果需要监听列表元素内部的更改,可以使用System.ComponentModel.BindingList

BindingList作用是将列表中元素内部的更改"转发"到外部。由于需要监听每个元素内部的属性更改,BindingList中的所有元素必须实现INotifyPropertyChanged

使用

现有Item类如下:

public partial class Item : ObservableObject
{[ObservableProperty]public partial string? Name { get; set; }[ObservableProperty]public partial int Value { get; set; }
}

Items列表中存储多个Item,如果需要计算列表中所有Value的总和,我们就可以使用BindingList

[ObservableProperty]
public partial BindingList<Item> Items { get; set; } = [];public int TotalValue => Items.Sum(i => i.Value);

然而修改Items中元素后,TotalValue并没有被更新,这是为什么呢?

事实上,BindingList并不能主动通知TotalValue属性。但它提供了十分强大的ListChanged事件,它在添加/删除元素或元素内部更改时均会触发(会根据更改类型会在ListChangedEventArgs中提供不同的ListChangedType),这是ObservableCollection无法做到的

public enum ListChangedType
{Reset,// 清空列表或列表行为变化(AllowNew/AllowEdit/AllowRemove发生改变)ItemAdded,// 添加元素ItemDeleted// 删除元素ItemMoved,// 移动元素ItemChanged,// 元素内部属性更改// BindingList未使用下面三个成员PropertyDescriptorAdded,PropertyDescriptorDeleted,PropertyDescriptorChanged
}

我们可以订阅此事件并完成对TotalValue的通知

public MainViewModel()
{// 此处OnPropertyChanged为MVVM工具包中ObservableObject的代码,可替换为PropertyChanged?.Invoke()Items.ListChanged += (s, e) => OnPropertyChanged(nameof(TotalValue));
}

现在,TotalValue在元素更改时就会重新计算,可直接用于单向绑定

缺陷以及解决方案

在Avalonia测试时,会发现一个很奇怪的现象:如果将BindingList作为列表控件的ItemSource使用,在添加/删除元素时,尽管TotalValue会被正确更新,但列表没有任何变化。同时,Count属性也没有得到正确通知

video_01

查看Avalonia中ItemSourceView的代码后发现,它只通过INotifyCollectionChangedCollectionChanged事件来刷新列表,而BindingList并未实现和INotifyCollectionChanged接口,这也就是为什么BindingList无法正确通知UI

同时,BindingList也未实现INotifyPropertyChanged,造成Count属性未更新

WinUI 3中,列表未刷新但Count属性能更新,可能是不同UI框架实现的问题

private protected void SetSource(IEnumerable source)
{...if (_listening && _source is INotifyCollectionChanged inccNew)CollectionChangedEventManager.Instance.AddListener(inccNew, this);
}

现在解决方法就很简单了:继承BindingList,实现这两个接口并在添加/移除元素进行通知即可。

完整代码如下:

public class ObservableBindingList<T> : BindingList<T>, INotifyCollectionChanged, INotifyPropertyChanged
{public event NotifyCollectionChangedEventHandler? CollectionChanged;public event PropertyChangedEventHandler? PropertyChanged;protected override void InsertItem(int index, T item){base.InsertItem(index, item);CollectionChanged?.Invoke(index, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]"));// 通知集合索引器的变化(通过索引器绑定列表第几项时使用)}protected override void RemoveItem(int index){var item = this[index];base.RemoveItem(index);CollectionChanged?.Invoke(index, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]"));}
}

使用:

[ObservableProperty]
public partial ObservableBindingList<Item> Items { get; set; } = [];public int TotalValue => Items.Sum(i => i.Value);public MainViewModel()
{   // 此处OnPropertyChanged为MVVM工具包中ObservableObject的代码,可替换为PropertyChanged?.Invoke()Items.ListChanged += (s, e) => OnPropertyChanged(nameof(TotalValue));
}

现在,增删(移动)元素/修改元素内部的值均可正确通知界面

video_02

示例代码

BindingListTest

http://www.hskmm.com/?act=detail&tid=20799

相关文章:

  • 谷歌 SEO 新词 xx animate 等实操教程
  • 完整教程:【读书笔记】架构整洁之道 P6 实现细节
  • Print Conductor打印软件安装教程!一款非常好用的批量打印软件!支持PDF、Word、Excel、图片等
  • Python 面向对象编程基础:类与对象初体验
  • 面向对象的设计原则
  • 反电动势法控制BLDC电机的原理图分析
  • 完整教程:Altium Designer(AD)设计规则检查设置
  • 企业物联网安全必须优先考虑的5个不可否认的理由
  • PSM敏捷认证自考学习指南
  • 2025内网聊天工具排行 4款好用的内网聊天软件推荐
  • 独立开发在线客服系统手记:实现对 PostgreSQL 的支持,以及与 MySQL 的对比
  • 方言普通话识别大模型,支撑中英+202种方言识别
  • ffmpeg一些使用记录,防止忘记
  • BLE从机(20)BLE区分主机(IOS/安卓/WIN)
  • Windows 驱动开发基础
  • 基于MATLAB实现基于距离的离群点检测算法
  • 国产DevOps工具链的突围之路:Gitee如何重塑企业研发效能
  • 阿里云抵御CC攻击利器边缘安全加速ESA
  • 生产者-消费者问题
  • Manim实现闪电特效
  • QAction的使用
  • Gitee:中国开发者生态的数字化转型加速器
  • 大模型提示词技巧Prompt Engineering,看这一篇就够了 - 知乎
  • sg.测试 PySimpleGUI 取值方法
  • Gitee DevOps:本土化基因驱动中国企业研发效能革命
  • 快速查看Navicat数据库连接密码实战
  • 老旧系统接入统一认证
  • 每周读书与学习-初识JMeter 元件(三)
  • Playwright MCP浏览器自动化全攻略
  • 【IEEE出版、连续3届稳定EI检索】第四届能源互联网及电力系统国际学术会议(ICEIPS 2025)