Хорошие примеры шаблона MVVM - PullRequest
136 голосов
/ 02 ноября 2009

В настоящее время я работаю с шаблоном Microsoft MVVM, и мне не хватает подробных примеров. Включенный пример ContactBook демонстрирует очень небольшую обработку команд, и единственный другой пример, который я нашел, взят из статьи в MSDN Magazine, где концепции похожи, но используют немного другой подход и все еще не имеют какой-либо сложности. Есть ли достойные примеры MVVM, которые хотя бы показывают базовые операции CRUD и переключение диалога / контента?


Все предложения были действительно полезны, и я начну составлять список хороших ресурсов

Каркасы / Templates

Полезные статьи

Screencasts

Дополнительные библиотеки

Ответы [ 9 ]

57 голосов
/ 11 ноября 2009

К сожалению, нет ни одного замечательного примера приложения MVVM, который бы делал все, и существует множество различных подходов к выполнению задач. Во-первых, вы можете ознакомиться с одной из существующих платформ приложений (Prism - достойный выбор), поскольку они предоставляют вам удобные инструменты, такие как внедрение зависимостей, команды, агрегация событий и т. Д., Чтобы легко опробовать различные шаблоны, которые вам подходят. ,

Выпуск призмы:
http://www.codeplex.com/CompositeWPF

Он включает в себя довольно приличное приложение с примерами (биржевой трейдер), а также множество небольших примеров и инструкции. По крайней мере, это хорошая демонстрация нескольких общих шаблонов, которые люди используют, чтобы заставить MVVM действительно работать. Я считаю, что у них есть примеры как для CRUD, так и для диалогов.

Призма не обязательно для каждого проекта, но с ней полезно ознакомиться.

CRUD: Эта часть довольно проста: двусторонние привязки WPF позволяют легко редактировать большинство данных. Настоящий трюк состоит в том, чтобы предоставить модель, которая облегчает настройку пользовательского интерфейса. По крайней мере, вы хотите убедиться, что ваш ViewModel (или бизнес-объект) реализует INotifyPropertyChanged для поддержки привязки, и вы можете привязывать свойства прямо к элементам управления пользовательского интерфейса, но вы также можете реализовать IDataErrorInfo для проверки. Как правило, если вы используете какое-то решение ORM, настройка CRUD совсем несложна.

Эта статья демонстрирует простые операции crud: http://dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx

Он построен на LinqToSql, но это не имеет отношения к примеру - все, что важно, это то, что ваши бизнес-объекты реализуют INotifyPropertyChanged (что делают классы, сгенерированные LinqToSql). MVVM не в этом примере, но я не думаю, что это имеет значение в этом случае.

Эта статья демонстрирует проверку данных
http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx

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

Большую часть времени вы можете взять объект (модель), созданный каким-либо ORM, и обернуть его в ViewModel, в котором он содержится, и командами для сохранения / удаления - и вы готовы привязать пользовательский интерфейс прямо к свойствам модели.

Представление будет выглядеть примерно так (ViewModel имеет свойство Item, которое содержит модель, как класс, созданный в ORM):

<StackPanel>
   <StackPanel DataContext=Item>
      <TextBox Text="{Binding FirstName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
      <TextBox Text="{Binding LastName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
   </StackPanel>
   <Button Command="{Binding SaveCommand}" />
   <Button Command="{Binding CancelCommand}" />
</StackPanel>

Диалоги: Диалоги и MVVM немного сложнее. Я предпочитаю использовать вид подхода Mediator с диалогами, вы можете прочитать немного больше об этом в этом вопросе StackOverflow:
Пример диалога WPF MVVM

Мой обычный подход, который не совсем классический MVVM, можно обобщить следующим образом:

Базовый класс для диалогового окна ViewModel, который предоставляет команды для принятия и отмены действий, событие, позволяющее представлению узнать, что диалог готов к закрытию, и все, что вам понадобится во всех ваших диалогах.

Общий вид для вашего диалога - это может быть окно или пользовательский «модальный» элемент управления типом наложения. По сути, это презентатор контента, в который мы помещаем модель представления, и он обрабатывает проводку для закрытия окна - например, при изменении контекста данных вы можете проверить, наследуется ли новый ViewModel от вашего базового класса, и если это так, подписаться на соответствующее событие закрытия (обработчик назначит результат диалога). Если вы предоставляете альтернативную универсальную функциональность закрытия (например, кнопка X), вы должны обязательно выполнить соответствующую команду закрытия и в ViewModel.

Где-то вам нужно предоставить шаблоны данных для ваших ViewModels, они могут быть очень простыми, тем более что у вас, вероятно, есть представление для каждого диалога, инкапсулированного в отдельный элемент управления. Шаблон данных по умолчанию для ViewModel будет выглядеть примерно так:

<DataTemplate DataType="{x:Type vmodels:AddressEditViewModel}">
   <views:AddressEditView DataContext="{Binding}" />
</DataTemplate>

Диалоговое представление должно иметь к ним доступ, потому что иначе оно не будет знать, как отобразить ViewModel, кроме общего интерфейса диалогового окна, его содержимое в основном таково:

<ContentControl Content="{Binding}" />

Неявный шаблон данных сопоставит представление с моделью, но кто его запускает?

Это не такая уж и мввм часть. Один из способов сделать это - использовать глобальное событие. Я думаю, что лучше всего использовать настройку типа агрегатора событий, предоставляемую посредством внедрения зависимостей - таким образом, событие является глобальным для контейнера, а не для всего приложения. Prism использует инфраструктуру Unity для семантики контейнера и внедрения зависимостей, и в целом Unity мне очень нравится.

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

Настройка этого таким образом позволяет ViewModels просить приложение открыть диалог и отвечать на действия пользователя там, ничего не зная об интерфейсе пользователя, поэтому по большей части MVVM-сущность остается завершенной.

Однако бывают случаи, когда пользовательский интерфейс должен вызывать диалоги, что может усложнить задачу. Рассмотрим, например, если позиция диалога зависит от расположения кнопки, которая ее открывает. В этом случае вам нужно иметь определенную информацию для пользовательского интерфейса при запросе открытия диалога. Я обычно создаю отдельный класс, который содержит ViewModel и некоторую соответствующую информацию пользовательского интерфейса. К сожалению, некоторая связь здесь кажется неизбежной.

Псевдокод обработчика кнопки, который вызывает диалоговое окно, которому нужны данные о положении элемента:

ButtonClickHandler(sender, args){
    var vm = DataContext as ISomeDialogProvider; // check for null
    var ui_vm = new ViewModelContainer();
    // assign margin, width, or anything else that your custom dialog might require
    ...
    ui_vm.ViewModel = vm.SomeDialogViewModel; // or .GetSomeDialogViewModel()
    // raise the dialog show event
}

Диалоговое представление будет привязано к данным позиции и передаст содержащуюся ViewModel во внутренний ContentControl. Сама ViewModel до сих пор ничего не знает об интерфейсе пользователя.

В общем случае я не использую возвращаемое свойство DialogResult метода ShowDialog() и не ожидаю, что поток будет блокироваться до закрытия диалога. Нестандартное модальное диалоговое окно не всегда работает таким образом, и в сложной среде вы часто не хотите, чтобы обработчик событий так или иначе блокировал это. Я предпочитаю позволить ViewModels справиться с этим - создатель ViewModel может подписаться на соответствующие события, установить методы commit / cancel и т. Д., Поэтому нет необходимости полагаться на этот механизм пользовательского интерфейса.

Итак, вместо этого потока:

// in code behind
var result = somedialog.ShowDialog();
if (result == ...

Я использую:

// in view model
var vm = new SomeDialogViewModel(); // child view model
vm.CommitAction = delegate { this.DoSomething(vm); } // what happens on commit 
vm.CancelAction = delegate { this.DoNothing(vm); } // what happens on cancel/close (optional)
// raise dialog request event on the container

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

6 голосов
/ 13 ноября 2009

Джейсон Долингер сделал хороший скринкаст из MVVM. Как упомянул Егор, нет ни одного хорошего примера. Они все кончены. Большинство из них являются хорошими примерами MVVM, но не тогда, когда вы сталкиваетесь со сложными проблемами. У каждого свой путь. У Лорана Бюньона есть хороший способ общения между моделями представления. http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx Cinch также хороший пример. У Пола Стоуела есть хорошая публикация , которая также многое объясняет с его фреймворком Magellan.

3 голосов
/ 24 апреля 2010

Нашел этот полезный. Имеет код тоже.

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

3 голосов
/ 02 ноября 2009

Вы смотрели на Калибурн ? Образец ContactManager содержит много хороших вещей. Типичные примеры WPF также дают хороший обзор команд. Документация довольно хорошая и форумы активны. Рекомендуется!

2 голосов
/ 07 ноября 2009

Я тоже поделился твоим разочарованием. Я пишу заявку, и у меня было 3 требования:

  • Extensible
  • WPF с MVVM
  • GPL совместимые примеры

Все, что я нашел, было кусочками, поэтому я просто начал писать это как мог. После того, как я немного углубился в это, я понял, что могут быть другие люди (например, вы), которые могут использовать эталонное приложение, поэтому я реорганизовал общий материал в среду приложения WPF / MVVM и выпустил его под LGPL. Я назвал это SoapBox Core . Если вы перейдете на страницу загрузок, то увидите, что она поставляется с небольшим демонстрационным приложением, и исходный код этого демонстрационного приложения также доступен для загрузки. Надеюсь, вы найдете это полезным. Кроме того, напишите мне на scott {at} soapboxautomation.com, если вам нужна дополнительная информация.

РЕДАКТИРОВАТЬ : Также опубликована статья CodeProject , объясняющая, как она работает.

2 голосов
/ 02 ноября 2009

Пример проекта в Cinch framework показывает базовые инструменты CRUD и навигации. Это довольно хороший пример использования MVVM и включает в себя статью из нескольких частей , объясняющую его использование и мотивы.

1 голос
/ 20 октября 2014

Я написал простой пример MVVM с нуля на код проекта, вот ссылка MVVM WPF шаг за шагом . Он начинается с простой 3-х уровневой архитектуры и позволяет вам использовать некоторые фреймворки, такие как PRISM.

enter image description here

1 голос
/ 19 июля 2014

Здесь я добавляю ссылку WPF (Inventory Management App) приложения , которое использует разработанную мной архитектуру MVVM

Его интерфейс потрясающий. https://github.com/shivam01990/InventoryManagement

1 голос
/ 07 февраля 2010

Даже я разделял разочарование, пока не взял дело в свои руки. Я запустил IncEditor.

IncEditor (http://inceditor.codeplex.com) - это редактор, который пытается познакомить разработчиков с WPF, MVVM и MEF. Я запустил его и сумел получить некоторые функции, например поддержку 'theme'. Я не эксперт в WPF или MVVM или MEF, поэтому я не могу добавить в него много функциональности. Я искренне прошу вас, ребята, сделать его лучше, чтобы такие, как я, сумасшедшие, могли лучше его понять.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...