ObservableCollection和Item PropertyChanged

Bil*_*ell 47 c# observablecollection

我已经看到很多关于这个问题的讨论,但也许我只是太多的新手才能得到它.如果我有一个可观察的集合,它是msdn示例中的"PersonNames"集合(http://msdn.microsoft.com/en-us/library/ms748365.aspx),如果a PersonName是,我会获得对View的更新添加或删除等.当我更改属性时,我想获得我的视图的更新PersonName.就像我改名字一样.我可以OnPropertyChanged为每个属性实现并让这个类派生出来INotifyPropertyChanged,并且似乎按预期调用.我的问题是,View如何从ObservableCollection更改属性获取更新数据不会导致任何事件ObservableCollection.这可能是非常简单的事情,但为什么我似乎无法找到一个令我惊讶的例子.任何人都可以为我阐明这一点,或者对示例有任何指示我会非常感激.我们在当前的WPF应用程序的多个位置都有这种情况,并且正在努力搞清楚.


"通常,负责显示数据的代码会为PropertyChanged当前显示在屏幕上的每个对象添加一个事件处理程序."

有人可以举个例子说明这意味着什么吗?我查看结合我ViewModel其中有一个ObservableCollection.此集合由RowViewModel具有支持PropertiesChanged事件的属性组成.但我无法弄清楚如何使集合更新自己,以便更新我的视图.

chi*_*emp 66

以下是如何附加/分离每个项目的PropertyChanged事件.

ObservableCollection<INotifyPropertyChanged> items = new ObservableCollection<INotifyPropertyChanged>();
items.CollectionChanged += items_CollectionChanged;

static void items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.OldItems != null)
    {
        foreach (INotifyPropertyChanged item in e.OldItems)
            item.PropertyChanged -= item_PropertyChanged;
    }
    if (e.NewItems != null)
    {
        foreach (INotifyPropertyChanged item in e.NewItems)
            item.PropertyChanged += item_PropertyChanged;
    }
}

static void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    throw new NotImplementedException();
}
Run Code Online (Sandbox Code Playgroud)

  • 无需检查e.OldItems!= null和e.NewItems!= null? (8认同)
  • 重置事件时,我认为这不起作用.因为他们没有填充旧项目. (4认同)
  • 这很漂亮.我一直在寻找这个,这对我很有帮助.非常感谢. (2认同)
  • 已经有一段时间了,我无法找到我为此示例抽象的来源.我想我正在使用静态的WPF依赖属性.我认为没有理由为什么这些函数不能成为每个实例. (2认同)

Joh*_*son 20

我们在WPF聊天中写了这个:

public class OcPropertyChangedListener<T> : INotifyPropertyChanged where T : INotifyPropertyChanged
{
    private readonly ObservableCollection<T> _collection;
    private readonly string _propertyName;
    private readonly Dictionary<T, int> _items = new Dictionary<T, int>(new ObjectIdentityComparer());
    public OcPropertyChangedListener(ObservableCollection<T> collection, string propertyName = "")
    {
        _collection = collection;
        _propertyName = propertyName ?? "";
        AddRange(collection);
        CollectionChangedEventManager.AddHandler(collection, CollectionChanged);
    }

    private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                AddRange(e.NewItems.Cast<T>());
                break;
            case NotifyCollectionChangedAction.Remove:
                RemoveRange(e.OldItems.Cast<T>());
                break;
            case NotifyCollectionChangedAction.Replace:
                AddRange(e.NewItems.Cast<T>());
                RemoveRange(e.OldItems.Cast<T>());
                break;
            case NotifyCollectionChangedAction.Move:
                break;
            case NotifyCollectionChangedAction.Reset:
                Reset();
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }

    }

    private void AddRange(IEnumerable<T> newItems)
    {
        foreach (T item in newItems)
        {
            if (_items.ContainsKey(item))
            {
                _items[item]++;
            }
            else
            {
                _items.Add(item, 1);
                PropertyChangedEventManager.AddHandler(item, ChildPropertyChanged, _propertyName);
            }
        }
    }

    private void RemoveRange(IEnumerable<T> oldItems)
    {
        foreach (T item in oldItems)
        {
            _items[item]--;
            if (_items[item] == 0)
            {
                _items.Remove(item);
                PropertyChangedEventManager.RemoveHandler(item, ChildPropertyChanged, _propertyName);
            }
        }
    }

    private void Reset()
    {
        foreach (T item in _items.Keys.ToList())
        {
            PropertyChangedEventManager.RemoveHandler(item, ChildPropertyChanged, _propertyName);
            _items.Remove(item);
        }
        AddRange(_collection);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(sender, e);
    }

    private class ObjectIdentityComparer : IEqualityComparer<T>
    {
        public bool Equals(T x, T y)
        {
            return object.ReferenceEquals(x, y);
        }
        public int GetHashCode(T obj)
        {
            return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
        }
    }
}

public static class OcPropertyChangedListener
{
    public static OcPropertyChangedListener<T> Create<T>(ObservableCollection<T> collection, string propertyName = "") where T : INotifyPropertyChanged
    {
        return new OcPropertyChangedListener<T>(collection, propertyName);
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 弱事
  • 跟踪多次添加到集合中的相同项目
  • 它〜气泡〜物业改变了孩子们的事件.
  • 静态类只是为了方便.

像这样使用它:

var listener = OcPropertyChangedListener.Create(yourCollection);
listener.PropertyChanged += (sender, args) => { //do you stuff}
Run Code Online (Sandbox Code Playgroud)


小智 13

法案,

我相信你现在已经找到了解决问题的方法或解决方案,但是我发布了这个针对这个常见问题的人.您可以将此类替换为ObservableCollections,它们是实现INotifyPropertyChanged的对象的集合.它有点严厉,因为它表示列表需要重置而不是找到已更改的一个属性/项,但对于小列表,性能命中应该是不可用的.

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;

namespace WCIOPublishing.Helpers
{
    public class ObservableCollectionWithItemNotify<T> : ObservableCollection<T> where T: INotifyPropertyChanged 
    {

        public ObservableCollectionWithItemNotify()
        {
            this.CollectionChanged += items_CollectionChanged;
        }


        public ObservableCollectionWithItemNotify(IEnumerable<T> collection) :base( collection)
        {
            this.CollectionChanged += items_CollectionChanged;
            foreach (INotifyPropertyChanged item in collection)
                item.PropertyChanged += item_PropertyChanged;

        }

        private void items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if(e != null)
            {
                if(e.OldItems!=null)
                    foreach (INotifyPropertyChanged item in e.OldItems)
                        item.PropertyChanged -= item_PropertyChanged;

                if(e.NewItems!=null)
                    foreach (INotifyPropertyChanged item in e.NewItems)
                        item.PropertyChanged += item_PropertyChanged;
            }
        }

        private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var reset = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
            this.OnCollectionChanged(reset);

        }

    }
}
Run Code Online (Sandbox Code Playgroud)


Jas*_*aty 4

正如您所发现的,没有集合级事件指示集合中项目的属性已更改。通常,负责显示数据的代码会将 PropertyChanged 事件处理程序添加到当前显示在屏幕上的每个对象。