Реализация CollectionChanged

Я добавил CollectionChanged eventhandler(onCollectionChanged) в одно из свойств ObservableCollection .

Я обнаружил, что метод onCollectionChanged вызывается только в случае добавления элементов или удаления элементов в коллекцию, но не в случае редактирования элемента коллекции.

Я хотел бы знать, как отправить список / коллекцию вновь добавленных, удаленных и отредактированных элементов в одной коллекции.

Благодарю.

Вы должны добавить слушателя PropertyChanged к каждому элементу (который должен реализовать INotifyPropertyChanged ), чтобы получить уведомление об изменении объектов в наблюдаемом списке.

 public ObservableCollection Names { get; set; } public List ModifiedItems { get; set; } public ViewModel() { this.ModifiedItems = new List(); this.Names = new ObservableCollection(); 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); } 

Возможно, вам нужно проверить, находится ли какой-либо элемент в списке ModifedItems-List (с помощью метода List Contains (object obj)) и добавлять только новый элемент, если результатом этого метода является false .

Элемент classа должен реализовать INotifyPropertyChanged . См. Этот пример, чтобы узнать, как это сделать. Как сказал Роберт Россни, вы также можете сделать это с помощью IEditableObject – если у вас есть это требование.

Элемент ItemsControl прослушивает CollectionChanged для управления отображением коллекции предметов, которые он представляет на экране. ContentControl прослушивает PropertyChanged для управления отображением определенного элемента, который он представляет на экране. Очень просто удержать эти две концепции в своем уме, как только вы это поймете.

Отслеживание того, редактируется элемент или нет, не является чем-то одним из этих интерфейсов. Изменения свойств не редактируются, т. Е. Они не обязательно представляют собой какое-то инициированное пользователем изменение состояния объекта. Например, у объекта может быть свойство ElapsedTime , которое постоянно обновляется таймером; пользовательский интерфейс должен быть уведомлен об этих событиях изменения свойств, но они, конечно же, не представляют изменения в базовых данных объекта.

Стандартный способ отслеживать, редактирован ли объект, – это сначала сделать этот объект реализацией IEditableObject . Затем вы можете внутренне перейти к classу объекта, решить, какие изменения представляют собой редактирование (т. BeginEdit вызова BeginEdit ), а какие нет. Затем вы можете реализовать логическое свойство IsDirty которое устанавливается, когда BeginEdit вызывается и очищается при CancelEdit 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 : ObservableCollection { 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)); } } 

Я думаю, что ObservableCollection элементами, которые реализуют INotifyPropertyChanged , вызовет событие CollectionChanged когда элемент вызывает уведомление PropertyChanged .

С BindingList , я думаю, вам нужно использовать BindingList чтобы отдельные изменения элементов распространялись таким образом из коробки.

В противном случае вам нужно будет вручную подписаться на уведомления об изменениях каждого элемента и поднять событие CollectionChanged . Обратите внимание: если вы создаете собственный, полученный ObservableCollection , вам придется подписаться на создание экземпляра и на Add() и Insert() и отказаться от подписки на Remove() , RemoveAt() и Clear() . В противном случае вы можете подписаться на событие CollectionChanged и использовать добавленные и удаленные элементы из аргументов событий для подписки / отмены подписки.

В winforms BindingList является стандартной практикой. в WPF и Silverlight вы обычно зацикливаетесь с ObservableCollection и должны прослушивать PropertyChanged для каждого элемента

Используйте следующий код:

-my Модель:

  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)); } } } 

И в моем classе PersonList реализует метод, ответственный за активное увеличение значения одного после нажатия кнопки в AppBarControl

 async private void Add_Click(object sender, RoutedEventArgs e) { List items = new List(); 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 Flavors; 

Самое простое решение, которое я нашел для этого ограничения, состоит в том, чтобы удалить элемент с помощью RemoveAt(index) затем добавить измененный элемент в тот же индекс, используя InsertAt(index) и поэтому ObservableCollection уведомит View.

  • Изменение цвета ячейки DataGrid на основе значений
  • Вставить событие в текстовом поле WPF
  • Как обновить GUI с помощью фонового рабочего?
  • Как сделать все элементы управления пропорционально пропорционально изменяемыми, когда окно максимизируется?
  • Как применить правило пользовательской сортировки к WPF DataGrid?
  • Как получить цвет из шестнадцатеричного цветового кода с помощью .NET?
  • Получить активный цвет автоматической цветовой темы Windows 8
  • WPF / MVVM - как обрабатывать двойной щелчок на TreeViewItems в ViewModel?
  • В моем приложении WPF мой загруженный логотип PNG на изображении отображается во время разработки, но не во время выполнения
  • Добавление элементов в столбцы в WPF ListView
  • Как я могу получить DPI в WPF?
  • Давайте будем гением компьютера.