Хорошие примеры шаблонов MVVM

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


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

<сильные > Каркасы/Шаблоны

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

Screencasts

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

Ответ 1

К сожалению, нет ни одного замечательного приложения 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 немного сложны. Я предпочитаю использовать аромат подхода "Посредник" с диалоговыми окнами, вы можете прочитать немного больше об этом в этом вопросе StackOverflow:
Пример диалога WPF MVVM

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

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

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

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

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

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

<ContentControl Content={Binding} />

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

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

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

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

Однако есть моменты, когда пользовательский интерфейс должен поднимать диалоги, что может сделать вещи немного сложнее. Рассмотрим, например, если позиция диалога зависит от местоположения кнопки, которая открывает его. В этом случае вам нужно иметь некоторую информацию о пользовательском интерфейсе, когда вы запрашиваете открытие диалога. Обычно я создаю отдельный класс, который содержит 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 все еще ничего не знает о пользовательском интерфейсе.

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

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

// 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

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

Ответ 2

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

Ответ 3

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

Ответ 5

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

Ответ 6

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

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

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

EDIT. Также опубликовано статья CodeProject, объясняющая, как это работает.

Ответ 7

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

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

Ответ 8

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

Его пользовательский интерфейс является удивительным. https://github.com/shivam01990/InventoryManagement

Ответ 9

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

enter image description here