Использование данных проектирования WPF с шаблоном MVVM
Я использую шаблон MVVM в нашем приложении WPF для всестороннего модульного тестирования. Сам шаблон MVVM работает отлично, однако я изо всех сил пытаюсь адаптировать шаблон таким образом, чтобы я мог использовать поддержку данных во время разработки WPF.
Так как я использую Prism, экземпляры ViewModel обычно внедряются в конструктор представления, например, так
public MyView(MyViewModel viewModel)
{
DataContext = viewModel;
}
Зависимости для ViewModel затем вводятся в конструктор, как
public class MyViewModel
{
public MyViewModel(IFoo foo, IBar bar)
{
// ...
}
// Gets and sets the model represented in the view
public MyModel { get; set; }
// Read-only properties that the view data binds to
public ICollectionView Rows { get; }
public string Title { get; }
// Read-write properties are databound to the UI and are used to control logic
public string Filter { get; set; }
}
Обычно это работает очень хорошо, за исключением случаев, когда речь идет о данных проектирования - я хотел избежать компиляции классов, специфичных для данных проектирования, в мою выпущенную сборку, и поэтому я решил использовать {d:DesignData}
подход вместо {d:DesignInstance}
подход, однако для того, чтобы это работало правильно, мой ViewModel теперь должен иметь конструктор без параметров. Кроме того, мне также часто приходится изменять дополнительные свойства, чтобы иметь наборы или изменяемые коллекции, чтобы иметь возможность устанавливать эти свойства в XAML.
public class MyViewModel
{
public MyViewModel()
{
}
public MyViewModel(IFoo foo, IBar bar)
{
// ...
}
// Gets and sets the model represented in the view
public MyModel { get; set; }
// My read-only properties are no longer read-only
public ObservableCollection<Something> Rows { get; }
public string Title { get; set; }
public string Filter { get; set; }
}
Это меня беспокоит
- У меня есть конструктор без параметров, который никогда не предназначен для вызова и не тестируется модулем
- Существуют сеттеры для свойств, которые должен вызывать только сам ViewModel.
- Моя ViewModel теперь представляет собой беспорядочную смесь свойств, которые должны быть изменены представлением, и тех, которые не должны - это сложно с первого взгляда определить, какой фрагмент кода отвечает за поддержание любого данного свойства.
- Установка определенных свойств во время разработки (например, чтобы увидеть стиль на
Filter
текст) может в конечном итоге вызвать логику ViewModel! (поэтому мой ViewModel также должен быть толерантным к отсутствующим обязательным зависимостям, отсутствующим во время разработки)
Есть ли лучший способ получить данные времени разработки в приложении WPF MVVM таким образом, чтобы таким образом не скомпрометировать мою ViewModel?
В качестве альтернативы я должен построить свою ViewModel по-другому, чтобы у него были более простые свойства с логикой, выделенной где-то еще.
2 ответа
Во-первых, я бы порекомендовал вам взглянуть на это видео, где Брайан Лагунас предлагает несколько лучших практик MVVM. Брайан - по крайней мере - участвует в разработке Prism, так как его имя появляется в информации о пакетах Nuget. Не проверял дальше.
Со своей стороны, я использую только биты Prism, а мои Model и ViewModel всегда предлагают пустые конструкторы (например, как показывает Брайан), контекст данных назначается в XAML представления, и я устанавливаю значения свойств следующим образом:
<MyView.DataContext>
<MyViewModel />
</MyView.DataContext>
а также
public void BringSomethingNew()
{
var myView = new View();
(myView.DataContext as ViewModel).Model = myModel;
UseMyView();
}
Еще одним преимуществом этого подхода является то, что ViewModel создается один раз, с тем же путем при проектировании и во время выполнения, поэтому вы создаете меньше объектов и экономите усилия по сборке мусора. Я нахожу это элегантным.
Что касается сеттеров, то данные проекта все равно будут работать, если вы сделаете их закрытыми, например:
public string MyProp { get; private set; }
Хорошо, настроить его для управления NotifyPropertyChange
на ваше удобство, но у вас есть идея.
Теперь у меня пока нет решения для управления ObesrvableCollection
s (я сталкиваюсь с той же проблемой, хотя помещение нескольких значений в XAML иногда работает...???), и да, я согласен, что вам приходится управлять случаем, когда свойства не заданы, как установкой значений по умолчанию в конструкторе,
Надеюсь, это поможет.
Я тоже работал с тестированием NUnit с реализацией WPF и MVVM. Тем не менее, моя версия противоположна вашей. Сначала вы создаете представление, а затем создаете модель для управления им.
В моей версии я создаю модель MVVM FIRST и могу тестировать ее до тех пор, пока коровы не вернутся домой и не будут беспокоиться о визуальном дизайне... если модель сломана, то и визуальная реализация тоже будет.
в моей модели MVVM у меня есть метод "GetTheViewWindow". Таким образом, когда я наследую свой базовый уровень MVVM, у каждой модели представления есть свой вид, за который она отвечает. Таким образом, с помощью виртуального метода каждый экземпляр будет создавать свое собственное новое окно представления при применении к производству.
public class MyMVVMBase
{
private MyViewBaseline currentView;
public MyMVVMBase()
{ // no parameters required }
public virtual void GetTheViewWindow()
{ throw new exception( "You need to define the window to get"; ) }
}
public class MyXYZInstanceModel : MyMVVMBase
{
public override void GetTheViewWindow()
{
currentView = new YourActualViewWindow();
}
}
Надеюсь, это поможет в качестве альтернативы тому, с чем вы сталкиваетесь.