Как поделиться несколькими ObservableCollections с несколькими ViewModels?

Я пишу программу с 4 представлениями: CompanyView, MembersView, WeeksView и ReportsView. У каждого есть соответствующие ViewModel и Model. Я использовал PRISM BindableBase для создания ViewModels. Данные связываются правильно.

  • CompanyViewModel содержит объект типа Company.
  • MembersViewModel содержит ObservableCollection объектов- членов.
  • WeeksViewModel содержит ObservableCollection объектов недели.

Навигация осуществляется с помощью верхних кнопок в главном окне, причем любой вид можно выбрать в любое время.

Container.RegisterTypeForNavigation<CompanyView>("CompanyView");
Container.RegisterTypeForNavigation<MembersView>("MembersView");
Container.RegisterTypeForNavigation<WeeksView>("WeeksView");
Container.RegisterTypeForNavigation<ReportsView>("ReportsView");

Проблема в том, что WeeksViewModel также должен иметь доступ к членам ObservableCollection. И ReportsViewModel также должен иметь доступ к объекту компании, членам ObservableCollection и неделям ObservableCollection.

Я не уверен, как это реализовать. Как я могу легко обмениваться данными между ViewModels?

Я попытался использовать PRISM IEventAggregator для публикации ObservableCollections при их обновлении, и это работает, однако сначала необходимо получить доступ к представлению, прежде чем оно сможет прослушивать событие. Если пользователь ранее не нажимал на представление "Недели", обновленная коллекция MembersCollection не достигнет WeeksView. Могу ли я предварительно инициализировать виды? Как бы я это сделал?

Я следил за MVVM Made Simple с помощью Prism - вебинар ( https://www.youtube.com/watch?v=ZfBy2nfykqY) и обнаружил ту же проблему, написанную в комментариях. Брайан Лагунас предлагает единственный способ исправить это с помощью параметров навигации:

У меня есть небольшая проблема с UpdateEvent, передавая сообщение из ViewAViewModel в ViewBViewModel. Кажется, это не работает, если я не посещал ViewB, я предполагаю, что это потому, что ViewBViewModel еще не был создан до тех пор, пока его представление не было загружено хотя бы один раз.

У кого-нибудь есть какие-либо идеи по этому поводу, я предполагаю, что создание экземпляров всех моделей представления до того, как они понадобятся, является плохой идеей, так как вы можете получить информацию по умолчанию в модель представления из других моделей представления до того, как она будет создана?

Брайан Лагунас: Единственный способ сделать это - передать эту информацию в качестве параметра при переходе к ViewBViewModel.

Я подумал об использовании параметров навигации, но, похоже, вы должны знать, от ГДЕ до ГДЕ вы перемещаетесь. Например, из MembersView > WeeksView передайте коллекцию Members в качестве параметра. Но пользователи могут осуществлять навигацию в любом порядке, в том числе непосредственно в WeeksView при загрузке программы. Например, как WeeksView получает коллекцию участников, если они пришли из представления компании? Компания не знает о Членах коллекции.

Я открыт для других идей, я исследовал повсюду и полностью застрял:-(

Большое спасибо за ваши идеи и помощь! С наилучшими пожеланиями, Дамиан

2 ответа

Решение

Проблема в том, что WeeksViewModel также должен иметь доступ к членам ObservableCollection. И ReportsViewModel также должен иметь доступ к объекту компании, членам ObservableCollection и неделям ObservableCollection.

Я не уверен, как это реализовать. Как я могу легко обмениваться данными между ViewModels?

Вы можете использовать одну модель представления со свойствами для каждой конкретной модели представления и общими свойствами, которые будут совместно использоваться двумя или более моделями представления, например:

class MainViewModel
{
    public CompanyViewModel CompanyViewModel { get; set; }
    public MembersViewModel MembersViewModel { get; set; }
    public WeeksViewModel WeeksViewModel { get; set; }

    public ObservableCollection<Members> Members { get; set; }
}

Тогда каждое из дочерних представлений может наследовать DataContext родительского окна и привязать к любому свойству, которое они хотят по всем типам модели представления.

Другим вариантом будет передача информации между моделями представления с использованием прямых ссылок, агрегатора событий или общего сервиса.

Но кажется бессмысленным отчаянно пытаться разделить логику между моделями представления, если они все еще должны иметь доступ к свойствам друг друга. Так что я бы, вероятно, пошел с первым подходом.

Я бы предложил сделать Company, ObservableCollection<Week> а также ObservableCollection<Member> исходить из одной или нескольких услуг.

WeeksViewModel затем получает ObservableCollection<Week> а также ObservableCollection<Member> от службы (ий) и обрабатывает данные для потребления WeeksView, ReportsViewModel процессы Company, ObservableCollection<Week> а также ObservableCollection<Member> для потребления ReportsView... Если кто-то добавляет Memberон делает это через службу, обладающую ObservableCollection<Member>и все модели просмотра, которые получили ObservableCollection<Member> от этого сервиса, получит уведомление и обновится соответственно.

Нет необходимости передавать данные между моделями представления, потому что модели представления не владеют данными. Все, что они когда-либо делают, - это преобразовывают данные из какого-либо источника данных для отображения, а наоборот - преобразуют действия пользователя в вызовы службы, которая модифицирует данные.

В тот момент, когда вы просматриваете модели с собственными данными, вы получаете такие методы, как UpdateData на моделях представления, и в конечном итоге вы получите непонятный код спагетти UpdateThis а также UpdateThat или одну модель мега-представления в стиле mm8, которая используется всеми видами. Вы этого не хотите.

Другие вопросы по тегам