Повторная реализация того же инициатора событий

Я пишу несколько классов и хочу сделать их «совместимыми с привязкой данных» (для WPF или даже, возможно, более редкого WinForms) путем реализации INotifyPropertyChanged.

Проблема в повторяющемся коде. На самом деле я копирую и вставляю один и тот же метод снова и снова (я не шучу).

protected void OnPropertyChanged([CallerMemberName] String propertyName = null)
{
    if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

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

Я думал о создании базового класса, который будет его реализовывать (может быть, NotifyPropertyChangedObject для имени), но это, вероятно, плохая идея, которая действительно ограничит мои классы без множественного наследования.
Я также думал о методе расширения, но я хотел бы ограничьте его как метод protected, так что это тоже не сработает.

Что можно сделать, чтобы решить эту проблему?


person MasterMastic    schedule 26.03.2013    source источник


Ответы (3)


Наличие базового класса — это метод, который используют даже вспомогательные библиотеки MVVM. В этом нет недостатка.

Да, у вас может быть только один базовый класс для класса С#, но он может реализовывать несколько интерфейсов. В вашем случае все, что вам нужно сделать, это сказать, что базовый класс реализует INPC и назовет его ViewModelBase

Теперь, если в настоящее время у вас есть класс X, наследуемый от класса A, просто сделайте A наследником ViewModelBase.

Таким образом, ваши текущие базовые классы наследуются от этого нового класса, предоставляющего INPC, и у вас нет дублирования кода для реализации INPC ни в одном из ваших производных классов.

Обновить

В вашем особом случае, когда вы по какой-либо причине уже привязаны к другому базовому классу и с ограничением не говорить что-то вроде общедоступной реализации INPC, переданной этому объекту в качестве переменной-члена,

Вы можете попробовать взглянуть на это:

Fody и, в частности, его дополнение PropertyChanged — дополнение

Мы надеемся, что это поможет вам, так как он вводит сами реализации INPC, таким образом, не требуя от вас копирования и вставки кода, а также позволяет вам наследовать любой пользовательский базовый класс (все еще нужно указать INPC, но здесь это просто интерфейс)

person Viv    schedule 26.03.2013
comment
Как насчет классов .NET? Они мне нужны, и я не могу заставить их наследовать мой базовый класс. - person MasterMastic; 26.03.2013
comment
О каких классах .Net идет речь? Если его представление связано (Window, UserControl, Button), вы просто подклассируете и добавляете к ним свойства зависимости, когда это необходимо. Я даже не внедряю в них INPC - person Viv; 26.03.2013
comment
Я говорю ровно об обратном. Классы, которые вообще не относятся к классам представлений или привязке данных. (Проще говоря: классы, которые не уведомляют об изменении). Как я могу наследовать эти классы, а также уведомлять об изменении моих (расширенных) полей без повторения метода в моем вопросе? Вот о чем мой вопрос (поэтому я еще не принял ваш ответ, что, тем не менее, фантастично). Кстати, если это невозможно сделать, это тоже будет ответом. - person MasterMastic; 26.03.2013
comment
ну, в этом случае вы как бы обделены, так как .net не допускает множественного наследования. Я обновлю ответ возможным обходным путем для этого особого случая. - person Viv; 26.03.2013

Обычно я привязываю свое представление к объекту типа модели представления, то есть к объекту, который содержит все данные, которые понадобятся представлению. Это упрощает работу с системой, поскольку представление должно быть привязано только к одному объекту.

Затем я обычно заставляю свои бизнес-объекты предоставлять данные модели представления и выставлять одно событие, чтобы уведомить модель представления об изменении ее состояния, и в этот момент модель представления будет вызывать для представления соответствующие уведомления, относящиеся к свойствам. т.е. вам нужно будет реализовать вышеуказанный метод только один раз для каждой модели представления/представления.

Изучите модель MVVM, если вы еще этого не сделали. Вышеизложенное является лишь одним из множества подходов и действительно является моей интерпретацией, с которой некоторые могут не согласиться и которая может соответствовать или не соответствовать вашему конкретному сценарию.

person Drew R    schedule 26.03.2013
comment
Чтобы проиллюстрировать мою точку зрения: используйте свойства, подобные этому, на виртуальной машине string _labelName; public string LabelName { get { return _labelName; } set { if (value == _labelName) return; _labelName = value; notifyPropertyChanged(); } }. - person Drew R; 26.03.2013

Чтобы добавить к ответу @viv. Если вы уже решили использовать Fody+PropertyChanged Я рекомендую избегать базового класса. Поскольку PropertyChanged выполняет всю реализацию INPC за вас, наличие базового класса на самом деле имеет очень мало значения. На самом деле боли больше, чем ценности. Просто добавьте атрибут PropertyChanged.ImplementPropertyChanged в свой класс, и все остальное будет сделано за вас.

[ImplementPropertyChanged]
public class Person 
{
    public string Name { get; set; }
}

Что касается классов, которыми вы не владеете и, следовательно, можете реализовать INPC. Лучший подход — создать повторяющийся класс, представляющий собой упрощенную версию каждого класса, к которому вы хотите привязаться. Вы можете читать и записывать значения при загрузке и завершении представления. Или, если вы хотите привязать только к определенным свойствам, просто поместите эти свойства в свою модель основного представления.

person Simon    schedule 30.03.2013