Добрый день.
ПредысторияИспользуя паттерн MVVM столкнулся с тем, что Model, который обычно считается DTO и в примерах то же самое, в моем случае больше подходит на Domain Model(или если быть точнее интерфейс, между Domain Model и Интерфейсом. Строиться архитектура На шаблоне Clean Architecture). С этим Domain Model работают и другие. По сути приложение на WPF является клиентом.
ВопросПри таком подходе Model должна давать знать ViewModel об изменениях в себе. Исходя из MVVM напрямую она это делать не может, поэтому использовать можно способы:
Т.к я выбрал способ 2, то как мне синхронизировать 2 коллекции?
Первое, что пришло в голову - использовать интерфейс IModel(название сущности), вынести его отдельно. Создать коллекцию ObservableCollection в Model, при создании VM получать ссылку на эту коллекцию с тем же интерфейсом и View пусть View работает через интерфейс с этой коллекцией. Тем самым я не синхронизирую 2 коллекции, а оставляю одну. Для реализации подобного в Model есть DataModelController, который является синглотоном, который занимается хранением и выдачей данных. В итоге ViewModel через Di получает от этого DataModelController эту коллекцию.
Почему так? Логически все круто, View не знает о Model(знает об интерфейсе IModel), Model не зависит от ViewModel(классы Model реализуют просто интерфейс).
Но тут начинаются проблемы, если ViewModel несколько сложнее, чем просто переопределение Model. Допустим появляются команды, разная логика у самого ViewModel классов. Придется юзать (ViewModel)IModel, что ведет за собой приведение, что ведет за собой создание нового объекта при приведении(потому что так это работает), что ведет за собой разсинхронизацию(которую можно частично решить путем того, что при приведение сохраняется ссылка на Model(IModel точнее).
Думал еще создать абстрактный класс и чтобы Model и ViewModel наследовали его, тогда при приведении(вроде) это будет один и тот же объект, просто под разным соусом.
Также можно построить иерархию интерфейсов IViewModel:IModel. Тогда это будут тоже один и тот же объект под разным соусом. Но тогда, возможно, будет не очень хорошо с точки зрения поддержки. Да и глубокая иерархия наследования интерфейсов ничем не лучше иерархии наследования классов. Да и встает так же вопрос поддержки этого другими, ибо вроде это не популярно. Тобишь встает вопрос поддержки не мной.
Намного легче для понимания синхронизация двух коллекций.
Update 2
Уточню вопрос путем примеров и самих уточнений.
Как видно на картинке, Model может изменяться не только Client'ом, но и сервером. Т.е может Client2 тоже сидит и следит за сервером.
Один из сценариев: Client1 отправил изменения на Server, Server сохранил данные отправил всем подписчикам(Client2). Далее по схеме. Данные проходят через ServieCommunicationController и попадают в Model. Model должен неявно уведомить ViewModel. ViewModel обновляет View. И наоборот. Model на Client является синхронизирующийся с Server слоем.
Ваши вопросы слегка философские, разные люди вам ответят по-разному. Отвечу из личного опыта:
Программы где Модель реализует INPC для нужд ViewModel в итоге становились сложно поддерживаемыми, сложно тестируемыми. Их приходилось переписывать.
Пишу модели так, как будто других слоев не существует. Модель содержит как базовые объекты, так и бизнес-логику. Пишу тесты на модель.
Сам факт того, ViewModel требует реализации INPC в модели уже говорит мне о том, что пора что-то менять. Изменение модели чаще всего является ответом на действие пользователя, то есть происходит из ViewModel. Может ли модель изменится другим путем, кроме как из ViewModel? Если да, то в модели должно быть соответствующее событие. Но чаще это не так. А раз ViewModel знает, что что-то произошло, зачем ждать реакции изменения с нижнего слоя, если можно просто запросить новое состояние измененной модели? Модель должна быть сама по себе.
Как организовать коммуникацию между несколькими ViewModel, не затрагивая при этом модель? Я знаю несколько вариантов:
Изменять модель через сервис. Сервис имеет событие, на которое можно подписаться другим ViewModel.
Сервис сообщает контроллеру, что надо обновить какие-то ViewModel.
Использовать паттерн EventAggregator
Ответ на конкретно ваш вопрос.
Так как вашего кода нет, придумаю свой. Заиспользуем гипотетический EventAggregator. Подписываемся на некое глобальное событие, которое вызывает изменение модели.
public class Model
{
public List<string> Values { get; set; }
}
public class ViewModel : NotifyPropertyChangedBase
{
private Model _model;
public Model Model
{
get { return _model; }
set
{
_model = value;
UpdateValues();
}
}
private void UpdateValues()
{
Values.Clear();
Values.AddRange(_model.Values);
}
public ViewModel(Model model, IEventAggregator eventAggregator)
{
_model = model;
eventAggregator.Subscribe<SomeProcessExecuted>(OnProcessExecuted);
}
private void OnProcessExecuted(object data)
{
UpdateValues();
}
public ObservableCollection<string> Values { get; } = new ObservableCollection<string>();
}
Виртуальный выделенный сервер (VDS) становится отличным выбором
Я создал базу и заполнил его с данными, но на экран не выводитсяКак правильно установить подключение:
Есть WPF приложение в котором строки дата грида нужно подсветить в зависимости от содержимого одной ячейкиДля этих целей написал конвертер...