MVVM Просмотреть ссылку на ViewModel

Я использую MVVM в приложении WPF. Я очень новичок в обоих. Позвольте мне заявить, что я не самый чистый в шаблоне MVVM, я стараюсь использовать как можно больше лучших практик, но я пытаюсь сделать то, что считаю разумным компромиссы, чтобы заставить его работать в нашей среде. Например, я не пытаюсь достичь 0% кода в моем представлении codebehind.

У меня есть пара вопросов о лучших практиках.

1) Я понимаю, что не хочу, чтобы моя виртуальная машина узнала о прикрепленном представлении, но разумно ли для представления иметь ссылку на свою виртуальную машину?

2) Если элемент управления в представлении открывает другой вид (например, диалог), я должен обрабатывать это в представлении? Кажется, что неправильно обрабатывать его в виртуальной машине с тех пор, как VM имеет некоторое представление о конкретном представлении.

Ответ 1

1) Вид определенно ссылается на ViewModel через DataContext. И вам разрешено использовать DataContext в вашем представлении:

public class ShellView : Window 
{
   …
   public ShellViewModel { get { return DataContext as ShellViewModel; } }

Это не является нарушением шаблона Model-View-ViewModel.

.

2) Вы правы. ViewModel не должен открывать другой вид. Лучше использовать контроллеры. Они несут ответственность за рабочий процесс приложения.

Если вас интересует более подробная информация, вы можете взглянуть на WPF Application Framework (WAF).

Ответ 2

1) Вот две простые практики для представления "зная о" ViewModel. Это разумно для представления, чтобы узнать о ViewModel (для привязки данных), но вам может и не понадобиться это в вашем случае. Посмотрите, поможет ли любой из этих подходов решить вашу проблему. Есть и другие способы, но они должны быть достаточно простыми:

public View(ViewModel vm)
{
     View.DataContext = vm;
}

public Bootstrapper(View v, ViewModel vm)
{
     v.DataContext = vm;
     //or, if you want it to have no parameters
     View v = new View();
     ViewModel vm = new ViewModel();
     v.DataContext = vm;
}

Первый вариант неплох, если у вас есть инструмент определения местоположения, но есть вкус MVVM, который не похож на какой-либо код в View Code-Behind. Второй вариант тоже неплох, должен быть достаточно прост для вашей задачи.

2.) Этот вопрос может быть немного липким моментом в дизайне MVVM. Если мы говорим об общем Win32 MessageBox, я часто разделяю эту логику на дополнительный объект и помещаю его в виртуальную машину. Этот путь имеет тенденцию к немного более ясному. (Например, я выбрал элемент в ListBox, я приложил команду Delete ICommand к этому действию, и в моей ViewModel, когда эта ICommand будет выполнена, я буду вызывать свой MessageBoxObject, чтобы спросить, действительно ли пользователь "хочет действительно удалить" это пункт). Более продвинутые "Диалоги" будут использовать дополнительные ViewModels и DataTemplates для этих ViewModels. Я предпочитаю подход Mediator.

Ответ 3

1). Представление потребует ссылки на модель представления на каком-то уровне, поскольку viewmodel будет выступать в качестве представления данных.

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

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

Ответ 4

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


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

Как уже было сказано, правильная компоновка View-ViewModel включает в себя ViewModel, назначаемую как свойство View DataContext. Это позволяет DataBindings "автоматически" устанавливаться из декларативного XAML или точно настраиваться с помощью кода позади.

Иногда у вас возникнет соблазн написать в вашем коде позади что-то вроде этого:

var dc = DataContext as CleverViewModel;
CleverViewModel.CleverProperty.Add(someValue); // just a simple example

Я считаю, что правильный способ достичь такого рода вещей - это не бросать DataContext, а вместо этого:

  • У вас есть выделенный элемент управления в представлении, например, элемент ItemsControl с двухсторонним привязкой данных ItemsSource к некоторому свойству в viewmodel:

    <ItemsSource x:Name="cleverControl" Visibility="Collapsed" ItemsSource="{Binding CleverProperty, Mode=TwoWay}"/>

  • Передайте свойство bound вместо всего ViewModel в коде позади:

    var collection = (ObservableCollection<double>)cleverControl.ItemsSource; collection.Add(someValue);

Обратите внимание на важное различие: второй подход в этом примере не требует, чтобы View знал тип ViewModel, ему нужно только свойство с именем CleverProperty типа ObservableCollection<double>. Это позволяет мне иметь полиморфные или даже типичные модели ViewModels.


Если элемент управления в представлении открывает другой вид (например, диалог), я должен обрабатывать это в представлении? Кажется, неправильно обрабатывать его в виртуальной машине с тех пор то VM имеет некоторое представление о конкретном представлении.

Это не должно происходить в строгом MVVM, и его не сложно избежать использования DataTemplates. DataTemplates отображает определенный тип DataContext для определенного типа представления, поэтому в любое время, когда изменяется тип данных ContentControl, его отображение также изменяется при условии, что у вас есть DataTemplate для этого типа:

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

  • Вид может содержать другой вид, не зная ViewModel. В этом случае код позади может манипулировать datacontext содержащегося представления.

Есть больше тонкостей, но я использовал этот подход с хорошими результатами. Надеюсь, это поможет кому-то.

Ответ 5

Создайте собственную MVVM-инфраструктуру

Я нашел подход, предложенный Роб Эйзенбергом, очень интересным.

Ключевые моменты:

  • Контекстная конфигурация
  • Сначала ViewModel

Что очень похоже на философию ASP.NET MVC.

Я очень рекомендую смотреть видео.