Событие ObservableCollection PropertyChanged - PullRequest
8 голосов
/ 16 июня 2009

ОК, поэтому я хочу создать подкласс ObservableCollection, чтобы добавить к нему свойство. К сожалению, событие PropertyChanged защищено. По сути, я хочу создать в подклассе SelectedItem, который можно связать для списков в моем приложении MVFM WPF.

Вот скелет моего класса:

public class SelectableList<T> : ObservableCollection<T>
{
    public T SelectedItem {get;set;}
}

Но я не могу сделать следующее:

SelectableList<int> intList = new SelectableList<int>();
intList.PropertyChanged += new PropertyChangedEventHandler(intList_Changed);

из-за ограничений доступа. Это заставляет меня задать более глубокий вопрос. Почему пользовательский интерфейс может получать уведомления о PropertyChanged событиях (например, свойство Count), а я не могу сделать это в коде позади?

У меня кружится голова, может кто-нибудь просветить меня?

Ответы [ 4 ]

10 голосов
/ 16 июня 2009
SelectableList<int> intList = new SelectableList<int>();
((INotifyPropertyChanged)intList).PropertyChanged += 
    new PropertyChangedEventHandler(intList_Changed);

ObservableCollection реализует INotifyPropertyChanged явно , что означает, что вы должны привести экземпляр к интерфейсу, прежде чем сможете получить доступ к методам, свойствам и событиям интерфейса. Что касается того, почему это сделано, я не знаю. Разметка Binding extensio n не «знает» ObservableCollections или любой другой тип. Он проверяет типы, чтобы увидеть, реализуют ли они или расширяют определенные интерфейсы / базовые классы (INPC, INCC, DependencyObject и т. Д.), И поэтому не заботится, реализован ли интерфейс явно.

8 голосов
/ 30 марта 2011

ObservableCollection (int .NET 3.5), по-видимому, реализует событие PropertyChanged интересным способом .

protected event PropertyChangedEventHandler PropertyChanged;

event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;

Это означает, что защищенное PropertyChanged событие, скорее всего, предназначено только для внутренней реализации. Другое событие INotifyPropertyChanged.PropertyChanged - это событие, которое фактически выполняет реализацию интерфейса INotifyPropertyChanged как явный интерфейс . Странно, но я не вижу ни одного места в ObservableCollection, где фактически вызывается INotifyPropertyChanged.PropertyChanged . Это может указывать на то, что это ошибка в .NET 3.5, хотя я не проверял, например, вызывается ли событие измененного свойства для Count при добавлении элемента в коллекцию, но похоже, что он должен работать .

В реализации .NET 4.0 кажется, что событие INotifyPropertyChanged.PropertyChanged вместо этого подключается к тому же частному делегату, который используется защищенным событием PropertyChanged , которое могло быть исправлением ошибки. Также возможно, что это просто из-за различий в способах автоматической реализации событий в .NET 4.0 .

Исправление: Я убедился, что событие INotifyPropertyChanged.PropertyChanged вызвано ObservableCollection, поэтому предположения, которые я сделал выше на основе результатов использования Reflector для проверки реализации ObservableCollection, должны быть неточный. Я предполагаю, что отражатель делает странную ошибку, у меня пока нет доказательств этого.

Таким образом, чтобы ваш пример работал, вам нужно написать, чтобы этот пример работал, и выглядел бы как пример ниже, как это продемонстрировал Уилл в своем ответе.

SelectableList<int> intList = new SelectableList<int>();
((INotifyPropertyChanged)intList).PropertyChanged += 
    new PropertyChangedEventHandler(intList_Changed);

Интересно, верно? Использование явных интерфейсов в основном используется, чтобы избежать неизбежных коллизий в элементах, необходимых для данного интерфейса, но они могут быть использованы в некотором смысле, чтобы скрыть существование элемента.

Если вы хотите вызвать события изменения свойств для своих собственных пользовательских свойств, которые вы вводите в своем подклассе, посмотрите на переопределение и / или вызов защищенного OnPropertyChanged метода, который также реализует ObservableCollection. Этот метод является хорошо принятым стандартом и позволяет подклассам вызывать события или обрабатывать события, не имея доступа к базовому делегату события. Обычно предпочитают использовать эту технику, кстати, вместо того, чтобы иметь обработчики событий ловушки подкласса к его собственным событиям базовых классов. Для большего количества примеров посмотрите, как события в различных элементах управления реализованы в WinForms и WPF.

1 голос
/ 28 декабря 2012

Я пытался добавить новое свойство в

public class ResultCollection<T> : ObservableCollection<T>
{

        Boolean _val;
        public Boolean Val
        {   
            get
            {   
                return _val;
            }
            set
            {   
                _val= value;
                OnPropertyChanged(new PropertyChangedEventArgs("Val"));
            }
        }
}

Я действительно не заметил, что PropertyChanged определяется как protected . Наконец, свойство Val перемещено в ViewModel.

0 голосов
/ 16 июня 2009

Пользовательский интерфейс может получать уведомления. Это ограничение JUST с ObservableCollection, которое определяет событие PropertyChanged как защищенное.

FWIW, я думаю, вам лучше оставить ObservableCollection в покое и просто добавить другое свойство в вашу виртуальную машину.

...