Взаимодействие между двумя и более ViewModel

266
10 декабря 2017, 09:05

Доброго времени суток, Господа. Прошу помочь мне в моем спаггети-коде и разложить все по полочкам. Суть следующая: Есть окно, в этом окне есть два контрола - Menu и Frame. Также имеется страница Page, которая указана в Frame. Меню представляет из себя выбор категорий, а страница, которая отображается в Frame, представляет из себя изделия:

Итак. У окна есть свой VM - WindowViewModel. В этом VM есть вложенное VM - MenuViewModel, которое является View Model'ом моего меню. У этого MenuViewModel есть открытое свойство:

Category selectedMenuItem;
public Category SelectedMenuItem
{
    get => selectedMenuItem;
    set { Set( ref selectedMenuItem, value ); }
}

которое представлет из себя выбранный пункт меню, и отражается на определенную категорию Category. До этого момент должно быть все понятно. Теперь страница:

Каждая страница наследуется вот от такого класса( не буду весь класс пилить сюда, оставлю только самое основное):

public class BasePage<VM> : Page where VM : BaseViewModel, new()
{
    VM viewModel;
    public VM ViewModel
    {
        get {  return viewModel; }
        set
        {
            if( viewModel == value )
                return;
            viewModel = value;
            this.DataContext = viewModel;
        }
    }
    public BasePage()
    {
        ViewModel = new VM();
    }
}

Итого мы имеем вот такую страницу, для отображения изделий:

public partial class ProductListPage : BasePage<ProductListViewModel>
{
    public ProductListPage() : base()
    {
        InitializeComponent();
    }
}

ProductListViewModel - это VM для страницы отображения изделий. Это большой класс, в котором написаны тонкости вывода изделий, поэтому не очень хочется приводить его здесь. Единственное что скажу, это то, что в конструкторе этого VM идет запрос у репозитория на получение всех изделий из БД, чтобы при первом старте страницы, отображались все товары, всех категорий.

А теперь собственно вопрос. Как правильно сделать взаимодействие между двумя VM'ами - MenuViewModel и ProductListViewModel. После изменения текущего пункта меню, в MenuViewModel срабатывает команда, в обработчике этой команды обновляется свойство SelectedMenuItem. Как теперь известить ProductListViewModel о том, что нужно отфильтровать список изделий? Меня не интересуют кривые решения этой проблемы. Я и сам могу это реализовать. Мне бы хотелось услышать изящные решения, которые я, возможно, буду применять в будущем. Спасибо

Answer 1

Окей, попробую ответить на этот вопрос в меру своего понимания.

Для взаимодействия VM-объектов между собой они должны быть связаны. Таким образом, между объектами должна существовать зависимость.

Для того, чтобы установить зависимость между объектами, есть много путей. Либо один из группы объектов (обычно «родительский») берёт на себя ответственность по созданию и настройке объектов-потомков, либо (если настройки и связи становятся слишком сложны, чтобы быть ответственностью одного VM-объекта) эта ответственность делегируется «внешнему», управляющему объекту, чьё единственное задание — связать VM-объекты между собой правильным образом.

Для того, чтобы один подобъект «узнал» о другом, я бы использовал традиционные средства «ручного» внедрения зависимостей: конструктор с нужными параметрами, на крайний случай — открытые для записи свойства. Полновесное внедрение зависимостей в моей практике использовать для простой цели связи VM-объектов не приходилось, и было практически всегда излишним.

Для вашего случая я бы связал MenuViewModel (или, возможно, лишь SelectedMenuItem) с ProductListPage, чтобы она могла сама следить за изменением SelectedMenuItem'а и надлежащим образом реагировать.

Важное замечание. Для того, чтобы возможно было связывание VM (да и просто в соответствии с паттерном MVVM, если вы его придержтваетесь), у вас VM-объекты наподобие ProductListViewModel не должны конструироваться во View, и должны иметь конструктор с параметрами. DataContext для окна должен устанавливаться самой программой, а DataContext для внутренних контролов должен в большинстве случаев устанавливаться через привязку к свойствам DataContext'а охватывающих контролов.

READ ALSO
Таймаут в фуллскрин моде между кликом на экране pause/play и даблкликом на экране - выход из фуллскрина

Таймаут в фуллскрин моде между кликом на экране pause/play и даблкликом на экране - выход из фуллскрина

Приветствую, хотел спросить: как тут сделать чтобы был таймаут между кликами по экрану - play/pause и даблкликом fullscreen ибо когда видео проигрывается...

316
Как получить объект из двух массивов?

Как получить объект из двух массивов?

В методе приходит два массива array1(id1

296
спрятать ссылку средствами javascript

спрятать ссылку средствами javascript

Требуется спрятать ссылку от поисковых систем, с помощью javascriptС целью более разумного распределения веса на странице

275