Обертывание свойств в свойства, совместимые с WPF, для реализации INotifyPropertyChanged.

В моем приложении WPF мой класс Model наследуется от класса ParentClass как такового:

Model : ParentClass, INotifyPropertyChanged

Мое приложение просто предназначено для предоставления пользовательского интерфейса для тестирования и проверки ParentClass. Так что Model на самом деле не более чем реализация INotifyPropertyChanged, наложенная на ParentClass.

Однако мне все еще нужно получить доступ к данным из этого родительского класса и заставить его реагировать на пользовательский интерфейс.

Предполагая, что Slicing является свойством в ParentClass, а WPFSlicing является свойством в Model, именно так я сейчас и делаю. Я оборачиваю каждое родительское свойство в свойство, совместимое с WPF.

public Thickness WPFSlicing
{
    get { return Slicing; }
    set
    {
        Slicing = value;
        OnPropertyChanged("Slicing");
    }
}

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


person William Thomas Waller    schedule 13.08.2014    source источник
comment
Да, вам нужно вызывать OnPropertyChanged(propertyName) для каждого установщика :(   -  person Jon    schedule 13.08.2014
comment
Кажется, у вас нет хорошего разделения для View, Model и ViewModel. Возможно, вы можете отредактировать свой вопрос, чтобы показать, какие из ваших классов соответствуют какому из доменов MVVM.   -  person Mare Infinitus    schedule 13.08.2014
comment
Разве не принято реализовывать INotifyPropertyChanged в модели?   -  person William Thomas Waller    schedule 13.08.2014
comment
вам это понадобится. Но, возможно, вы ищете это. msdn.microsoft.com/en-us/library/ms165394.aspx   -  person Core-One    schedule 13.08.2014
comment
Я не уверен, насколько эта ссылка актуальна, @Core-One   -  person William Thomas Waller    schedule 13.08.2014
comment
Если ваша версия VS поддерживает макросы (или альтернативы макросов), я считаю, что быстрее всего просто записать макрос, который запишет все вещи изменения собственности для меня. У меня есть пример здесь, если вам интересно.   -  person Rachel    schedule 13.08.2014
comment
Если ваша модель имеет свойства типа Thickness и другие подобные типы, специфичные для пользовательского интерфейса, то вы на самом деле не используете MVVM, и поэтому делаете все, что хотите, черт возьми, - это не имеет значения.   -  person    schedule 13.08.2014
comment
ParentClass — это данные для рендеринга, которые можно использовать вне моего приложения. В контексте моего приложения это все еще просто данные модели.   -  person William Thomas Waller    schedule 13.08.2014


Ответы (2)


Это очень интересный вопрос.

Как правило, я обнаружил, что в приложениях MVVM вы пытаетесь изолировать модель как конечный результат — продукт/часть данных — модели представления. Например, если бы у вас был магазин велосипедов, вы бы увидели витрину магазина как вид, продавца как модель представления (при условии, что это настраиваемый велосипед, созданный на заказ), а модель как готовый объект велосипеда.

В случае создания велосипеда, пока он находится на стадии «прототипирования», которую необходимо представить, я стараюсь оборачивать его в ViewModel — потому что в этом есть логика. Это кажется дополнительным шагом, но, в конце концов, вы можете проводить проверки в этой ViewModel при ее создании. Если ваша модель негибкая для добавления к ней INotifyPropertyChanged (или если она была сгенерирована из службы), у вас будут проблемы, если у вас на велосипеде шины «0» — это должно вызвать проблемы!

Многие люди, как правило, становятся немного ленивее и рассматривают MVVM как шаблон, который абстрагирует прототипированные модели (где ввод данных идет вперед/назад, обновляется) в модели — когда они на самом деле должны быть ViewModels.

В примере у меня будет каталог MVVM, который выглядит так:

Models
  -Bicycle (an object that can be passed across a service, etc -- data)
Views
  -BicycleCreatorView (the view or data template of the model)
  -StoreFrontView (the view of the entire store/app)
ViewModels
  -BicycleCreatorViewModel (the view model which CONSTRUCTS a Bicycle model as the end     result)
  -StoreFrontViewModel (the view model for the entire store)

Теперь вы могли бы очень легко ТАКЖЕ иметь конструктор BicycleCreatorViewModel, который принимает модель велосипеда и предварительно заполняет ее. Это не редкость. Кто-то может прийти в магазин и сказать: «Эй, ты можешь сделать это похожее на другое? Вот как это выглядит». В то время как конечным результатом является наличие другого свойства (возможно, просто get {}), которое фактически отображает объект Bicycle, проверка IF хороша, и у нас нет чего-то необычного с 0 шинами, без сиденья (может быть, это особенность?) , и т.д.

Итак, короче говоря, я всегда хотел бы, чтобы ваша модель (если вы не можете расширить ее ЛЮБЫМ способом) была заключена в ее СОБСТВЕННУЮ ViewModel для этой цели. Это был бы настоящий шаблон MVVM. Вы всегда можете использовать такие вещи, как ReactiveUI или другие инструменты, которые могут обернуть свойства. Вы можете потратить на это немного больше времени, но конечный продукт будет гораздо более гибким и менее подверженным ошибкам, чем в противном случае. По сути, вы уже делаете это, но вы, вероятно, могли бы переписать его, чтобы он казался «чище» и нарисовал линию.

Теоретически вы также можете проверить, можете ли вы подойти к этому с помощью такого метода:

Есть ли аспектно-ориентированный инструментарий, который вы могли бы потенциально использовать? Может быть, сделать ваши классы частичными, чтобы включить INotifyPropertyChanged в расширение, а затем XmlIgnore определенные части, если сериализация является проблемой/вопросом?

Проблема в том, что у нас очень мало знаний о том, откуда берется модель и как вы ее используете. Надеюсь, что это поможет или даст вам интересную идею. Хотелось бы посмотреть, придумаете ли вы решение, более «вдохновленное», чем стандартное.

person Locke    schedule 13.08.2014
comment
Спасибо за длинный ответ! На самом деле я даже не думал о Model как о ViewModel для ParentClass, но теперь, когда я об этом думаю, это действительно так. - person William Thomas Waller; 13.08.2014

Предлагаю альтернативную точку зрения. Все это можно очень просто решить с помощью AOP-фреймворка, такого как PostSharp. Все, что вы делаете, это прикрепляете атрибут [NotifyPropertyChanged] к вашему классу, и в вашей модели все подключено.

http://www.postsharp.net/aspects/examples/inotifypropertychanged

Имейте в виду, хотя, это стоит, но это может быть хорошей инвестицией, imo.

Ps, это вопрос зрения, но я не вижу ничего плохого в том, чтобы все классы модели DOMAIN реализовывали INotifyPropertyChanged. Это не убивает производительность, единственным недостатком является то, что это немного загромождает код. Это то, что я сделал, мои объекты модели предметной области реализуются из CommonEntity и INotifyPropertyChanged. INotifyPropertyChanged не является частью WPF!

Это работает и определенно лучше, чем обертывание ваших моделей внутри моделей просмотра.

person Erti-Chris Eelmaa    schedule 13.08.2014
comment
На самом деле я всего лишь стажер, а ParentClass — это класс, который очень разозлит людей, если я прикоснусь к ним, ха-ха. В противном случае я бы обязательно рассмотрел ParentClass реализацию INotifyPropertyChanged - person William Thomas Waller; 13.08.2014
comment
Мне нравится это решение для АОП, но если ваш контракт заблокирован, вы не можете просто украсить контракт тегом. Я согласен с тем, что АОП предоставляет много интересных функций, но если вы застряли в том, что ваша модель исходит из чего-то, что находится вне вашего контроля (скажем, DLL уровня связи с контрактами), единственный реальный выбор — это создать что-то. Но вместо вопроса приведенный выше ответ является интересным способом избежать написания всех дополнительных вызовов OnNotifyPropertyChanged и т. д. - person Locke; 14.08.2014