Страницы

Поиск по вопросам

вторник, 27 ноября 2018 г.

Несколько вопросов по паттерну MVVM

Навели меня на мысль, что весь мой код является "говнокодом", потому что мои WPF приложения не соответствуют паттерну MVVM. Я начал про это читать, но в интернетах информация изложена слишком сложно для моего понимания. Поэтому я задам несколько вопросов, которые откроют мне глаза (я надеюсь)
Допустим, я создаю UserControl. При этом UserControl.xaml является View, а UserControl.xaml.cs - ViewModel? Или ViewModel - это еще один дополнительный класс, например UserControlViewModel? Я пока склоняюсь ко второму варианту, но не уверен. Если в прошлом вопросе правильным является второй вариант, то где мне создавать DependenceProperties? В UserControl.xaml.cs или в UserControlViewModel? Я пока склоняюсь к первому варианту. Если UserControl содержит команды, которые надо добавить к главному меню окна, в котором его расположили, то как это лучше осуществить, не отклоняясь от MVVM? Причем сделать это надо с иерархией. Первое, что приходит на ум - создать в ресурсах UserControl новое Menu. но при слиянии иерархию надо сохранить. То есть если в главном окне уже есть меню "Файл", и оно используется в контроле, то элементы контрола должны добавиться к элементам этого меню в окне без создания еще одного меню "Файл".
UPD:
И еще, что такое Model?
UPD2:
К примеру, мне надо вывести в ListBox коллекцию экземпляров класса MyClass
public class MyClass { public string Prop1 { get; set; } public string Prop2 { get; set; } }
в виде Prop1(Prop2)
Как мне поступить, чтобы соответствовать MVVM?
Раньше я делал так

Получается, что это неверный подход? Или что?
UPD3:
Еще вопрос. Вью и вью-модель связываются, например, через DataСontext вьюшки (других способов я не знаю). В этом случае вью-модель не имеет параметров у конструктора. А как тогда связать вью-модель и модель?
UPD4:
У меня еще вопрос. Вот есть у меня модель, вью-модель и вью. Вью-модель подписана на изменение свойств модели (хоть через PropertyChanged, хоть через отдельные события). Тогда получится следующее. Во вьюшке чего то меняется (пользователь изменил текст в текстовом поле). Через биндинг это передается в сеттер вью-модели, в которой написано следующее _model.Property = value. Но я ведь подписан на изменение свойств модели. Получается, что модель после изменения Property сообщит вью-модели, что ее свойство изменилось, вью-модель вызовет PropertyChanged и во вьюшке применится это значение в текстовом поле. По сути ничего страшного не произойдет, кроме того, что программа выполнит ЛИШНИЕ ДЕЙСТВИЯ


Ответ

Модель представления - это еще один дополнительный класс. Представление не обязательно должно быть UserControl'ом. Это может быть, например, словарь ресурсов с шаблоном данных для модели представления. Тогда ни о каком code-behind речи быть не может. Свойства зависимости нужно создавать в code-behind контрола (т.е. UserControl.xaml.cs). Это часть представления и модели представления о них знать не нужно. UserControl не должен содержать команды. Он должен привязываться к командам модели представления. Если нужна иерархия, то делайте иерархию команд в модели представления плагина (предполагаю, что вы делаете что-то плагинообразное) и сливайте их с командами модели представления главного окна. Еще я бы посоветовал избавиться от иерархии команд и подумать над тем, как их можно представить плоским списком.
UPD
Я согласен с Discord, потому и посоветовал делать плоский список. Это может быть набор команд в модели представления: OpenFileCommand, SaveFileCommand и т.д. А в представлении это уже будет иерархией: меню файл содержит пункты "открыть" и "сохранить".
Если у вас ситуация, когда пол проекта написана на WinForms, а половина на WPF, то, возможно, ваше решение вполне подходит. Просто после переноса проекта нужно не забыть переделать эту часть.
Когда мы перетаскивали проект в WinForms на WPF, то сначала изменили главное окно приложения: оно научилось работать с плагинами и формировать меню из них. Все компоненты на WinForms мы обернули в WindowsFormsHost А потом уже переделывали плагины на WPF по одному.
Модель - это то, для чего вы делали модель представления (например, какой-нибудь объект из БД). Примерно так: модель - то, что нужно показать пользователю; представление - то, что видит пользователь; модель представления - связующее звено с командами и доп. свойствами, необходимыми для корректной работы представления.
UPD2
С ходу довольно сложно придумать нормально решение, а на практике с именно такой задачей я не сталкивался. Например, вы можете сделать пачку интерфейсов типа:
// команды, расширяющие пункт меню "Файл". interface IFileCommandsProvider { List Commands { get; } }
А потом: если вкладка реализует этот интерфейс, то добавить перечень команд в меню.
Либо подумать над вариантом с чем-то вроде RegionManager'а из Prism
UPD4
В описанном вами случае эти действия выполнять не надо. Если по какой-то причине (например, чтобы повесить атрибуты валидации), вы хотите спрятать свойство модели за свойством модели представления, то в модели представления имеет смысл написать следующий код:
public int Property { get { return _model.Property; } set { if (_model.Property != value) { _model.Property = value; OnPropertyChanged(); } } }
Тогда всю работу со свойством Property внутри модели представления нужно будет осуществлять через свойство модели представления. Т.е. кода _model.Property = value больше нигде не должно встречаться. Тогда вам не нужно будет подписываться на Model.PropertyChanged("Property").

Комментариев нет:

Отправить комментарий