Использование данных проекта 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();
   }
}

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