实现CollectionChanged

Who*_*nja 26 c# wpf mvvm mvvm-light

我已添加CollectionChanged eventhandler(onCollectionChanged)到其中一个ObservableCollection属性.

我发现onCollectionChanged只有在添加项目或将项目移除到集合的情况下才会调用该方法,但是在集合项目被编辑的情况下则不会.

我想知道如何在一个集合中发送新添加,删除和编辑的项目的列表/集合.

谢谢.

Arx*_*sos 49

您必须为PropertyChanged每个项目(必须实现INotifyPropertyChanged)添加一个侦听器,以获取有关在可观察列表中编辑对象的通知.

public ObservableCollection<Item> Names { get; set; }
public List<Item> ModifiedItems { get; set; }

public ViewModel()
{
   this.ModifiedItems = new List<Item>();

   this.Names = new ObservableCollection<Item>();
   this.Names.CollectionChanged += this.OnCollectionChanged;
}

void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.NewItems != null)
    {
        foreach(Item newItem in e.NewItems)
        {
            ModifiedItems.Add(newItem);

            //Add listener for each item on PropertyChanged event
            newItem.PropertyChanged += this.OnItemPropertyChanged;         
        }
    }

    if (e.OldItems != null)
    {
        foreach(Item oldItem in e.OldItems)
        {
            ModifiedItems.Add(oldItem);

            oldItem.PropertyChanged -= this.OnItemPropertyChanged;
        }
    }
}

void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    Item item = sender as Item;
    if(item != null)
       ModifiedItems.Add(item);
}
Run Code Online (Sandbox Code Playgroud)

也许你必须检查一些项目是否已经存在于ModifedItems-List中(使用List的方法Contains(object obj)),并且只有在该方法的结果为false时才添加新项目.

该班Item必须实施INotifyPropertyChanged.请参阅此示例以了解具体方法.正如罗伯特罗斯尼所说,IEditableObject如果你有这个要求,你也可以这样做.

  • 除非您修改代码以检查e.NewItems和e.OldItems是否为null,然后再尝试使用它们,否则这将在Add和Remove操作上抛出异常. (2认同)
  • 当您有 Names 集合时,为什么需要此 ModifiedItems 列表? (2认同)

Rob*_*ney 10

一个ItemsControlCollectionChanged来管理它的呈现在屏幕上项目集合的显示.A ContentControl侦听PropertyChanged管理其在屏幕上显示的特定项目的显示.一旦理解了这两个概念,就很容易将这两个概念分开.

跟踪是否编辑项目不是这些接口中的任何一个.属性更改不是编辑 - 也就是说,它们不一定表示某种用户启动的对象状态更改.例如,一个对象可能具有一个ElapsedTime由计时器不断更新的属性; UI需要通知这些属性更改事件,但它们当然不代表对象底层数据的更改.

跟踪对象是否被编辑的标准方法是首先使该对象实现IEditableObject.然后,您可以在对象的类内部,决定哪些更改构成编辑(即需要您调用BeginEdit)以及哪些更改不会.然后,您可以实现一个布尔IsDirty是被当设置属性BeginEdit被调用时被清零EndEdit或者CancelEdit被调用.(我真的不明白为什么这个属性不属于IEditableObject我;我还没有实现一个不需要它的可编辑对象.)

当然,如果你不需要它,就没有必要实现第二级抽象 - 你当然可以监听PropertyChanged事件,并假设对象在被引发时已被编辑.这实际上取决于您的要求.


Beh*_*imi 6

我对“这个答案”的编辑被拒绝了!所以我把我的编辑放在这里:

void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
    foreach(Item newItem in e.NewItems)
    {
        ModifiedItems.Add(newItem);

        //Add listener for each item on PropertyChanged event
        if (e.Action == NotifyCollectionChangedAction.Add)
            newItem.PropertyChanged += this.ListTagInfo_PropertyChanged;
        else if (e.Action == NotifyCollectionChangedAction.Remove)
            newItem.PropertyChanged -= this.ListTagInfo_PropertyChanged;
    }
}

// MSDN: OldItems:Gets the list of items affected by a Replace, Remove, or Move action.  
//if (e.OldItems != null) <--- removed
}
Run Code Online (Sandbox Code Playgroud)