Использование данных проекта 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
- My ViewModel теперь представляет собой смешавшуюся смесь свойств, которая должна быть изменена в представлении, а те, которые не должны - это делает сложным рассказать с первого взгляда, какая часть кода отвечает за поддержание любого заданного свойства
- Настройка определенных свойств во время разработки (например, просмотр стиля в тексте
Filter
) может фактически вызвать логику ViewModel! (поэтому мой ViewModel также должен быть tollerant иначе обязательных зависимостей, отсутствующих во время разработки)
Есть ли лучший способ получить данные о времени разработки в приложении MVP MVF MVPM таким образом, чтобы это не нарушало мою ViewModel таким образом?
В качестве альтернативы я должен строить свой ViewModel по-разному, чтобы он имел более простые свойства с логикой, выделенной где-то в другом месте.
Ответы
Ответ 1
Во-первых, я бы порекомендовал вам взглянуть на это видео, где Брайан Лагунас предлагает несколько лучших практик в отношении MVVM. Брайан, по крайней мере, участвует в разработке Prism, так как его имя появляется в информации о пакетах nuget. Не проверял далее.
На моей стороне я использую только бит Prism, и моя модель и ViewModel всегда предлагают пустые конструкторы (например, что показывает Брайан), контекст данных назначается в представлении XAML, и я устанавливаю значения свойств, например:
<MyView.DataContext>
<MyViewModel />
</MyView.DataContext>
и
public void BringSomethingNew()
{
var myView = new View();
(myView.DataContext as ViewModel).Model = myModel;
UseMyView();
}
Другим преимуществом такого подхода является то, что ViewModel создается один раз, с тем же путем в дизайне и времени выполнения, поэтому вы создаете меньше объектов и сохраняете усилия GC. Я нахожу это элегантным.
Что касается установщиков, данные дизайна будут по-прежнему работать, если вы сделаете их приватными, например:
public string MyProp { get; private set; }
Хорошо, настройте его для управления NotifyPropertyChange
в удобное для вас время, но у вас есть идея.
Теперь у меня еще нет решения для управления ObesrvableCollection
(я сталкиваюсь с той же проблемой, хотя иногда несколько значений в XAML работают...???), и да, я согласен, что вы должны управлять случаем, когда свойства не заданы, например, задавать значения по умолчанию в конструкторе.
Надеюсь, это поможет.
Ответ 2
Я тоже работал с тестированием NUnit с реализацией WPF и MVVM. Однако моя версия отменена с вашего. Сначала вы создаете представление, а затем создаете модель для ее управления.
В моей версии я создаю модель MVVM FIRST и могу unit test до тех пор, пока корова не вернутся домой и не переживут о каком-либо визуальном дизайне... если модель сломана, также будет визуальная реализация.
в моей модели 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();
}
}
Надеюсь, это поможет в качестве альтернативы тому, с чем вы работаете.