WPF字典集合类ObservableDictionary
WPF最核心的技术优势之一就是数据绑定。数据绑定,可以通过对数据的操作来更新界面。
数据绑定最经常用到的是ObservableCollection<T> 和 Dictionary<T, T> 这两个类。
ObservableCollection表示一个动态数据集合,在添加项、移除项或刷新整个列表时,此集合将提供通知,可以通过更新集合数据来更新界面显示。
Dictionary字典类,检索和数据操作性能极性,所以一些配置项的集合都使用它来保存。
因此,大家就想到的,有没有ObservableCollection和Dictionary相结合的类呢,于是就形成的ObservableDictionary类。
网上有很多版本的ObservableDictionary类,据我了解到的,最早且最经典的就是Dr.WPF里面的ItemsControl to a dictionary,其他的版本多数是参考这个来修改的(不对的那就是我孤陋寡闻了)。
今天我提供的这个版本,也是参考了网上的其他版本和Dr.WPF里的。
Dr.WPF里的定义是这样的:
1 2 3 4 5 6 7 8 9 10 11 | public class ObservableDictionary <TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, INotifyCollectionChanged, INotifyPropertyChanged |
大家细心点就会发现,这里继承的接口和Dictionary<TKey, TValue>所继承的大部分相同,只是多了INotifyCollectionChanged, INotifyPropertyChanged
于是,今天我提供的版本,就直接继承于Dictionary<TKey, TValue>和INotifyCollectionChanged, INotifyPropertyChanged。
本人测试过,无BUG,性能也极佳,下面上代码:
public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged { public ObservableDictionary() : base () { } private int _index; public event NotifyCollectionChangedEventHandler CollectionChanged; public event PropertyChangedEventHandler PropertyChanged; public new KeyCollection Keys { get { return base .Keys; } } public new ValueCollection Values { get { return base .Values; } } public new int Count { get { return base .Count; } } public new TValue this [TKey key] { get { return this .GetValue(key); } set { this .SetValue(key, value); } } public TValue this [ int index] { get { return this .GetIndexValue(index); } set { this .SetIndexValue(index, value); } } public new void Add(TKey key, TValue value) { base .Add(key, value); this .OnCollectionChanged( new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, this .FindPair(key), _index)); OnPropertyChanged( "Keys" ); OnPropertyChanged( "Values" ); OnPropertyChanged( "Count" ); } public new void Clear() { base .Clear(); this .OnCollectionChanged( new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); OnPropertyChanged( "Keys" ); OnPropertyChanged( "Values" ); OnPropertyChanged( "Count" ); } public new bool Remove(TKey key) { var pair = this .FindPair(key); if ( base .Remove(key)) { this .OnCollectionChanged( new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, pair, _index)); OnPropertyChanged( "Keys" ); OnPropertyChanged( "Values" ); OnPropertyChanged( "Count" ); return true ; } return false ; } protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if ( this .CollectionChanged != null ) { this .CollectionChanged( this , e); } } protected void OnPropertyChanged( string propertyName) { if ( this .PropertyChanged != null ) { this .PropertyChanged( this , new PropertyChangedEventArgs(propertyName)); } } #region private方法 private TValue GetIndexValue( int index) { for ( int i = 0; i < this .Count; i++) { if (i == index) { var pair = this .ElementAt(i); return pair.Value; } } return default (TValue); } private void SetIndexValue( int index, TValue value) { try { var pair = this .ElementAtOrDefault(index); SetValue(pair.Key, value); } catch (Exception) { } } private TValue GetValue(TKey key) { if ( base .ContainsKey(key)) { return base [key]; } else { return default (TValue); } } private void SetValue(TKey key, TValue value) { if ( base .ContainsKey(key)) { var pair = this .FindPair(key); int index = _index; base [key] = value; var newpair = this .FindPair(key); this .OnCollectionChanged( new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newpair, pair, index)); OnPropertyChanged( "Values" ); OnPropertyChanged( "Item[]" ); } else { this .Add(key, value); } } private KeyValuePair<TKey, TValue> FindPair(TKey key) { _index = 0; foreach ( var item in this ) { if (item.Key.Equals(key)) { return item; } _index++; } return default (KeyValuePair<TKey, TValue>); } private int IndexOf(TKey key) { int index = 0; foreach ( var item in this ) { if (item.Key.Equals(key)) { return index; } index++; } return -1; } #endregion } |
扩展方面,大家可以以Dr.WPF版本来修改,那个更加有技术含量和可扩展性更强!
分类:
WPF
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南