Кто-нибудь знает, почему этот код не работает:
public class CollectionViewModel : ViewModelBase {
public ObservableCollection<EntityViewModel> ContentList
{
get { return _contentList; }
set
{
_contentList = value;
RaisePropertyChanged("ContentList");
//I want to be notified here when something changes..?
//debugger doesn't stop here when IsRowChecked is toggled
}
}
}
public class EntityViewModel : ViewModelBase
{
private bool _isRowChecked;
public bool IsRowChecked
{
get { return _isRowChecked; }
set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); }
}
}
ViewModelBase
содержит все для RaisePropertyChanged
и т. д., и работает для всего остального, кроме этой проблемы ..
c#
observablecollection
inotifypropertychanged
Джозеф Джун Melettukunnel
источник
источник
Ответы:
Метод Set ContentList не будет вызываться при изменении значения внутри коллекции, вместо этого вы должны искать срабатывание события CollectionChanged .
Хорошо, сегодня уже дважды я был укушен ошибкой документации MSDN. В ссылке, которую я дал вам, это говорит:
Но на самом деле он не срабатывает при смене предмета. Я думаю, вам понадобится более грубый метод, чем:
Если вам это понадобится очень часто, вы можете захотеть создать свой собственный подкласс,
ObservableCollection
который запускаетCollectionChanged
событие, когда член запускает егоPropertyChanged
автоматически (как сказано в документации ...)источник
changed
? Это может означать, что свойство одного из элементов в коллекции изменилось (как я думаю, вы его интерпретируете), или это может означать, что один из элементов коллекции был изменен путем замены его другим экземпляром ( это моя интерпретация). Не полностью убежден, хотя - придется изучить это дальше._contentList.Clear()
? Никто не откажется от подпискиPropertyChanged
!ContentCollectionChanged
только обрабатывает Add / Remove, а не Replace / Reset. Я постараюсь отредактировать и исправить сообщение. То, как Саймон делает это в своем ответе, правильно.Вот раскрывающийся класс, который подклассов ObservableCollection и фактически вызывает действие Reset при изменении свойства элемента списка. Он применяет все элементы для реализации
INotifyPropertyChanged
.Преимущество заключается в том, что вы можете привязывать данные к этому классу, и все ваши привязки будут обновляться с изменениями свойств вашего элемента.
источник
NotifyCollectionChangedAction.Replace
это не очень хорошая идея, потому что тогда вы не сможете различить фактически заменяемый элемент или событие, вызванное изменением элемента. Становится намного лучше, когда вы определяете,public event PropertyChangedEventHandler CollectionItemChanged;
а потомItemPropertyChanged
делаетеthis.CollectionItemChanged?.Invoke(sender, e);
Я собрал, как я надеюсь, довольно надежное решение, включая некоторые приемы в других ответах. Это новый класс, производный от
ObservableCollection<>
которого я называюFullyObservableCollection<>
Он имеет следующие особенности:
ItemPropertyChanged
. Я сознательно держал это отдельно от существующихCollectionChanged
:ItemPropertyChangedEventArgs
которая сопровождает это: оригиналPropertyChangedEventArgs
и индекс в коллекции.ObservableCollection<>
.ObservableCollection<>.Clear()
), избегая возможной утечки памяти.OnCollectionChanged()
, а не более ресурсоемкую подписку наCollectionChanged
событие.Код
Полный
.cs
файл следует. Обратите внимание, что было использовано несколько функций C # 6, но это должно быть довольно просто сделать бэкпорт:Тесты NUnit
Таким образом, вы можете проверить изменения, которые вы можете внести (и посмотреть, что я тестировал в первую очередь!), Я также включил мой тестовый класс NUnit. Очевидно, что следующий код не нужен просто для использования
FullyObservableCollection<T>
в вашем проекте.NB Тестовый класс использует
BindableBase
PRISM для реализацииINotifyPropertyChanged
. Нет зависимости от ПРИЗМЫ от основного кода.источник
ListView
будет реагировать наCollectionChanged
события, потому что знает о них.ItemPropertyChanged
это нестандартное дополнение, поэтому вам нужно научить этому. В качестве быстрого и грязного решения, вы можете попробовать запуститьCollectionChanged
событие так же, как (или даже вместо),ItemPropertyChanged
вOnItemPropertyChanged()
. Я держал их отдельно по причинам, указанным в ответе, но для вашего случая использования он может просто делать то, что вам нужно.Это использует вышеупомянутые идеи, но делает его производной «более чувствительной» коллекцией:
источник
ObservableCollection не будет распространять изменения отдельных элементов как события CollectionChanged. Вам нужно будет либо подписаться на каждое событие и переслать его вручную, либо вы можете проверить класс BindingList [T] , который сделает это за вас.
источник
Добавлено в TruelyObservableCollection событие «ItemPropertyChanged»:
источник
Я использовал ответ Джека Кениона для реализации своего собственного OC, но я хотел бы указать на одно изменение, которое я должен был сделать, чтобы заставить его работать. Вместо того:
Я использовал это:
Кажется, что «e.NewItems» выдает ноль, если действие .Remove.
источник
Просто добавляю мои 2 цента по этой теме. Чувствовал, что TrulyObservableCollection потребовал двух других конструкторов, как найдено с ObservableCollection:
источник
Я знаю, что я опоздал на эту вечеринку, но, может быть, это кому-то поможет ..
Здесь вы можете найти мою реализацию ObservableCollectionEx. У него есть некоторые особенности:
Конечно, любые комментарии приветствуются;)
источник
Если я знаю, что ObservableCollection создает событие только тогда, когда мы добавляем / удаляем или перемещаем элементы в нашей коллекции. Когда мы просто обновляем некоторые свойства в коллекции элементов коллекции, не сигнализируем об этом, и пользовательский интерфейс не будет обновляться.
Вы можете simly реализовать INotifyPropertyChange в классе модели. И тогда, когда мы обновим некоторые свойства в элементе коллекции, он автоматически обновит интерфейс.
и тогда
В моем случае я использовал ListView для Bind для этой коллекции и в ItemTemplate установил свойство Binding to Model, и оно работало хорошо.
Вот небольшой фрагмент
Windows XAML:
Пример кода модели:
И реализация ViewModel:
источник
Простое решение для стандартной наблюдаемой коллекции, которое я использовал:
НЕ ДОБАВЛЯЙТЕ в свою собственность ИЛИ ИЗМЕНЯЙТЕ ее внутренние предметы ПРЯМО, вместо этого создайте некоторую временную коллекцию, подобную этой
и добавлять элементы или вносить изменения в tmpList,
затем передайте его вашей фактической собственности по назначению.
это изменит целое свойство, которое вызывает уведомление INotifyPropertyChanged, как вам нужно.
источник
Я пробую это решение, но оно работает только для меня, как RaisePropertyChange («SourceGroupeGridView»), когда коллекция изменена, которая запускается для каждого добавления или изменения элемента.
Проблема в:
NotifyCollectionChangedAction.Reset это действие делает полное повторное связывание всех элементов в groupedgrid, эквивалентно в RaisePropertyChanged. При его использовании все группы gridview обновляются.
Если вам нужно только обновить в пользовательском интерфейсе группу нового элемента, вы не используете действие «Сбросить», вам нужно будет смоделировать действие «Добавить» в itemproperty примерно так:
Извините за мой английский, и спасибо за базовый код :), я надеюсь, что это поможет кому-то ^ _ ^
Enjoi !!
источник
Вот метод расширения для вышеуказанного решения ...
источник
Вместо ObservableCollection или TrulyObservableCollection рассмотрите возможность использования BindingList и вызова метода ResetBindings.
Например:
Учитывая событие, такое как щелчок, ваш код будет выглядеть так:
Моя модель выглядела так:
источник
BindingList
, но есть ограничение этого подхода, которое преодолевают другие ответы: этот метод основан на изменении значения в коде иResetBindings()
возможности добавления вызова . Большинство других ответов будут работать, если объекты списка будут изменены с помощью других средств, таких как неизменяемый код или привязка ко второму элементу управления.Для запуска OnChange в списке наблюдаемых коллекций
Пример:
источник
Вот моя версия реализации. Он проверяет и выдает ошибку, если объекты в списке не реализуют INotifyPropertyChanged, поэтому не могут забыть эту проблему при разработке. Снаружи вы используете событие ListItemChanged, чтобы определить, изменился ли список или сам элемент списка.
источник
Простое решение в 2 строки кода. Просто используйте конструктор копирования. Нет необходимости писать TrulyObservableCollection и т. Д.
Пример:
Еще один метод без конструктора копирования. Вы можете использовать сериализацию.
источник
Вы также можете использовать этот метод расширения, чтобы легко зарегистрировать обработчик для изменения свойства элемента в соответствующих коллекциях. Этот метод автоматически добавляется ко всем коллекциям, реализующим INotifyCollectionChanged, которые содержат элементы, которые реализуют INotifyPropertyChanged:
Как пользоваться:
источник