我已经向一个ObservableCollection
属性添加了CollectionChanged事件处理程序(onCollectionChanged)
。
我发现只有在向集合中添加或移除项目时,才会调用onCollectionChanged
方法,但如果编辑集合项,则不会调用。
我想知道如何将新添加、删除和编辑的项目列表/集合发送到单个集合中。
谢谢。
我已经向一个ObservableCollection
属性添加了CollectionChanged事件处理程序(onCollectionChanged)
。
我发现只有在向集合中添加或移除项目时,才会调用onCollectionChanged
方法,但如果编辑集合项,则不会调用。
我想知道如何将新添加、删除和编辑的项目列表/集合发送到单个集合中。
谢谢。
你需要为每个对象添加一个 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);
}
< p >可能需要检查某些项是否已经在ModifiedItems列表中(使用列表的Contains(object obj)方法),并且只有在该方法的结果为false时才添加一个新的项。类必须实现INotifyPropertyChanged
。请参阅此示例以了解如何实现。正如Robert Rossney所说,如果您有该要求,还可以使用IEditableObject
来实现。
ItemsControl
监听CollectionChanged
来管理它在屏幕上呈现的项目集合的显示。一个ContentControl
监听PropertyChanged
来管理它在屏幕上呈现的特定项的显示。一旦你理解了这一点,很容易将两个概念分开记忆。ElapsedTime
属性;UI需要被通知这些属性更改事件,但它们肯定不代表对象底层数据的更改。IEditableObject
。然后,在对象类内部,可以决定哪些更改构成编辑(即需要调用BeginEdit
),哪些更改不构成编辑。然后可以实现布尔值的IsDirty
属性,当调用BeginEdit
时设置该属性,并在调用EndEdit
或CancelEdit
时清除该属性。(我真的不明白为什么这个属性不是IEditableObject
的一部分;我还没有实现不需要它的可编辑对象。)PropertyChanged
事件,并假定如果引发了该事件,则对象已经被编辑了。这确实取决于你的需求。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
}
INotifyCollectionChanged
与INotiftyPropertyChanged
不是同一概念。改变基础对象的属性并不意味着集合已经发生了改变。
实现这种行为的一种方法是创建一个自定义集合,在添加对象时对其进行询问,并注册INotifyPropertyChanged.PropertyChanged
事件;在删除项目时,还需要适当地取消注册。
使用这种方法的一个注意事项是,当您的对象嵌套N层深时,需要使用反射来查询每个属性,以确定它是否可能是另一个实现INotifyCollectionChanged
或其他需要遍历的容器的集合。
以下是一个未经测试的基本示例...
public class ObservableCollectionExt<T> : ObservableCollection<T>
{
public override event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged;
protected override void SetItem(int index, T item)
{
base.SetItem(index, item);
if(item is INotifyPropertyChanged)
(item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged);
}
protected override void ClearItems()
{
for (int i = 0; i < this.Items.Count; i++)
DeRegisterINotifyPropertyChanged(this.IndexOf(this.Items[i]));
base.ClearItems();
}
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
RegisterINotifyPropertyChanged(item);
}
protected override void RemoveItem(int index)
{
base.RemoveItem(index);
DeRegisterINotifyPropertyChanged(index);
}
private void RegisterINotifyPropertyChanged(T item)
{
if (item is INotifyPropertyChanged)
(item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged);
}
private void DeRegisterINotifyPropertyChanged(int index)
{
if (this.Items[index] is INotifyPropertyChanged)
(this.Items[index] as INotifyPropertyChanged).PropertyChanged -= OnPropertyChanged;
}
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
T item = (T)sender;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset, item));
}
}
System.ArgumentException: 'Reset action must be initialized with no changed items.'
- tjmoore我认为使用实现了INotifyPropertyChanged
接口的项目来填充ObservableCollection
将会导致当项目引发其PropertyChanged
通知时,CollectionChanged
事件被触发。
仔细想想,我认为你需要使用BindingList<T>
来使单个项目的更改自动传播。
否则,您需要手动订阅每个项目的更改通知并触发CollectionChanged
事件。请注意,如果您创建自己的派生ObservableCollection<T>
,则必须在实例化和Add()
和Insert()
上订阅,并在Remove()
、RemoveAt()
和Clear()
上取消订阅。否则,您可以订阅CollectionChanged
事件并使用事件参数中添加和删除的项目来订阅/取消订阅。
BindingList
是标准做法。在WPF和Silverlight中,你通常会被迫使用ObservableCollection
并需要监听每个项目的PropertyChanged
。-我的模型:
public class IceCream: INotifyPropertyChanged
{
private int liczba;
public int Liczba
{
get { return liczba; }
set { liczba = value;
Zmiana("Liczba");
}
}
public IceCream(){}
//in the same class implement the below-it will be responsible for track a changes
public event PropertyChangedEventHandler PropertyChanged;
private void Zmiana(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
async private void Add_Click(object sender, RoutedEventArgs e)
{
List<IceCream> items = new List<IceCream>();
foreach (IceCream item in IceCreamList.SelectedItems)
{
int i=Flavors.IndexOf(item);
Flavors[i].Liczba =item.Liczba+ 1;
//Flavors.Remove(item);
//item.Liczba += 1;
// items.Add(item);
// Flavors.Add(item);
}
MessageDialog d = new MessageDialog("Zwiększono liczbę o jeden");
d.Content = "Zwiększono liczbę o jeden";
await d.ShowAsync();
IceCreamList.SelectedIndex = -1;
}
}
我希望这对某人有用 请注意:
private ObservableCollection<IceCream> Flavors;
-
RemoveAt(index)
删除该项,然后使用InsertAt(index)
在相同的索引上添加修改后的项,这样ObservableCollection将会通知视图。