MVVM — определение того, какая ViewModel за что отвечает

У меня есть простое приложение, состоящее из:

Модель

  • Предметы
  • Критерии фильтрации, примененные к этому списку элементов

Просмотры

  • Страница приветствия
  • ГлавнаяЭлементыСтраница
  • ФильтрРедактироватьСтраницу

Я использую MVVM Light и Windows Phone 7.

В настоящее время у меня есть 3 ViewModels, по одному для каждого представления. В прошлом у меня была одна ViewModel, которая делала общение, о котором я собираюсь спросить, очень простым. Однако я хотел использовать 3 отдельные виртуальные машины, поскольку это кажется правильным путем.

Страница приветствия может установить один из критериев фильтра перед переходом на страницу MainItemsPage. MainItemsPage привязан к свойству Items, которое предоставляется его ViewModel. Эта ViewModel должна отфильтровать этот список в зависимости от текущих критериев фильтрации. Страница FilterEditPage позволяет пользователю редактировать полный набор критериев из 4 переменных. Когда критерии изменены, необходимо повторно отфильтровать коллекцию Items, используемую в ViewModel для MainItemsPage.

Вопрос в том, как я пропускаю изменения фильтра через приложение. Я знаю, что в MVVM есть концепция обмена сообщениями, а инструментарий MVVM Light предоставляет класс Messenger. Однако то, с чем я борюсь, заключается в том, где лежит ответственность за отправку этих сообщений?

  1. Переходят ли 3 виртуальные машины к модели всякий раз, когда им нужно работать с текущим набором фильтров?
  2. Проходят ли все обновления фильтра через модель FilterEditViewModel, которая, в свою очередь, передает сообщение об изменении фильтра?
  3. Можно ли вернуться к одной виртуальной машине для всех представлений?

Я не вижу, чтобы 1. работало, потому что что-то должно будет вызвать виртуальные машины, чтобы вернуться к модели, которую я знаю, что могу заставить 3. работать прямо сейчас без проблем. Это неправильно?

ТИА

Пэт Лонг


person Pat Long - Munkii Yebee    schedule 25.08.2010    source источник


Ответы (2)


Я бы поместил общий текущий фильтр в модель, а не в модель представления. У вас есть много viewModel потенциально на разных страницах или на одной странице (рассмотрите навигационную цепочку, показывающую текущий выбор, и что-то еще, что должно показать, что фильтр был применен).

Как насчет одноэлементной модели для фильтра, на которую могут подписаться модели представлений?

person LittleColin    schedule 25.08.2010

Три виртуальные машины — правильный путь в вашем сценарии. Я предлагаю вам построить отношения «родитель-потомок» между вашими виртуальными машинами. Поскольку MainVM содержит ItemList, это место, где применяются FilterChanges. FilterEditVM только получает изменения фильтра, а затем вызывает MainVM, который должен повторно применить фильтры.

Структура будет примерно такой:

public class WelcomePageVM
{
    public WelcomePageVM()
    {
        this.FilterEditPageVM = new FilterEditPageVM(this);
        this.MainItemsVM = new MainItemsVM(this);
    }

    public FilterEditPageVM FilterEditPageVM { get; private set; }

    public MainItemsVM MainItemsVM { get; private set; }

    public void SetInitialFilter1(object filter)
    {
        // the initial filter
        this.FilterEditPageVM.Filter1Value = filter;
        this.MainItemsVM.ApplyFilters();
    }
}

public class FilterEditPageVM : ChildViewModelBase<WelcomePageVM>
{
    public FilterEditPageVM(WelcomePageVM parent)
        : base(parent) { }

    public object Filter1Value { get; set; }
    public object Filter2Value { get; set; }
    public object Filter3Value { get; set; }
    public object Filter4Value { get; set; }

    public void FinishFilterChange()
    {
        this.Parent.MainItemsVM.ApplyFilters();
    }
}

public class MainItemsVM : ChildViewModelBase<WelcomePageVM>
{
    public MainItemsVM(WelcomePageVM parent)
        : base(parent) { }

    public List<object> ItemList { get; set; }

    public void ApplyFilters()
    {
        // filter apply logic
    }
}

public abstract class ChildViewModelBase<T>
{
    T _parent;

    public ChildViewModelBase(T parent)
    {
        this._parent = parent;
    }

    public T Parent { get { return _parent; } }
}

Здесь вы можете получить доступ ко всем моделям просмотра, и это нормально, потому что вы остаетесь на уровне «контроллера».

person JanW    schedule 25.08.2010
comment
P.S: Добавлен FinishFilterChange() в FilterEditVM - person JanW; 25.08.2010
comment
Спасибо. Я вижу, что все это работает, но кажется неправильным, что маленькая старая страница WelcomePage является родителем, но я думаю, что это я попал в какое-то недопонимание и неправильное применение семантики. Вы установили WelcomePage в качестве родителя, потому что это первый загруженный экран (представление)? - person Pat Long - Munkii Yebee; 25.08.2010
comment
Точно. Конечно, с помощью приведенного выше шаблона вы можете свободно выбирать свой корень. Но я рекомендую использовать первое представление в качестве корня, потому что это имеет смысл, если ваша модель контроллера представляет способы, которыми вы можете следовать в графическом интерфейсе. Если вы просмотрите свое приложение через некоторое время, вам будет легче понять рабочий процесс. Если вам не нравится ваша страница приветствия в качестве пользователя root, я предлагаю вам создать еще один настоящий RootView, в котором вы переключаете три других представления. Затем этот конкретный RootView будет обладать всеми тремя вышеуказанными моделями ViewModel. - person JanW; 25.08.2010