MVVM Datagrid обновлен из представления и модели - PullRequest
0 голосов
/ 13 декабря 2011

У меня есть сетка данных, которая привязывается к объекту Item, который реализует INotifyPropertyChanged.

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

Некоторые из моих опасений:

Где мне позвонить write в службе устройства, из ViewModel или из объекта Item? Как убедиться, что значение, отображаемое в сетке данных, «отредактировано» после редактирования до получения события от устройства?

Некоторые мысли

  1. Если это объект Item, то объект Item больше не DTO, а, скорее всего, ViewModel. Таким образом, у меня будет две модели представления для одного представления (пользовательский контроль) Один для пользовательского элемента управления и один для элементов в сетке данных. Это не соответствует моему пониманию модели представления. Но, возможно, это не так? И как же тогда Item узнает, было ли значение обновлено из представления (пользователем) или модели представления (службой устройства)?

  2. ViewModel подписывается на PropertyChanged для объекта Item. Чтобы определить, изменилось ли значение из View, ViewModel может отписаться от PropertyChanged или установить флаг при получении событий из сервиса. Вроде комковато, но сработает. Возможно, мне следует сделать два свойства: ViewValue и ServiceValue. ViewModel должен обновить ServiceValue и подписаться на ViewValue, где он может вернуть ViewValue в ServiceValue после прочтения.

  3. View обрабатывает CellEditEnding и уведомляет модель представления

Ответы [ 2 ]

2 голосов
/ 13 декабря 2011

Относительно пункта 1): Да, используйте ViewModel для привязки к пользовательскому интерфейсу, а не к DTO.Это основная идея, помогающая отделить данные от представления в MVVM.

Что касается пунктов 2) и 3) Я предлагаю вам реализовать интерфейс IEditableObject в ваших моделях представления, возможно, в общем базовом классе..

Этот интерфейс предоставляет методы BeginEdit(), CancelEdit(), and EndEdit().Использование этих методов дает вам четкий и читаемый контроль над тем, когда какой объект изменяется и когда отправлять эти изменения, например, в службу или базу данных.

Кроме того, реализация этих методов дает вам механизм для обработки этих различныхВерсии данных, такие как "ViewValue" и "ServiceValue".Вы можете создать локальную копию ServiceValue в качестве запасного при вызове метода BeginEdit() и вызвать это локальное запасное значение при вызове метода CancelEdit().Если вызывается EndEdit(), это время для отправки значений обратно в службу, после чего сохраняется текущее значение в этом локальном временном значении в качестве нового запасного значения.

Изменить надобавить ответ по пункту 1)

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

Обычно мы организуемViewModels таким образом, что у нас есть одна ViewModel для представления, которая содержит всю информацию для определенного представления.Давайте назовем это «основной ViewModel».Если нам нужна иерархия представлений, мы реализовали бы иерархию моделей представления, которые следуют той же иерархии.

В случае, подобном вашему, мы поместили бы DataGrid в другой UserControl, который содержится в основном представлении.Основная ViewModel будет содержать другую ViewModel, которая снова содержит данные, необходимые для DataGrid.Эта ViewModel будет установлена ​​как DataContext этого DataGrid-UserControl.Таким образом, вы по-прежнему сохраняете чистое разделение по одному на ViewModel-per-View.

В этом случае можно настроить дополнительное форматирование данных в DataGrid va Templates.

1 голос
/ 13 декабря 2011

1) Обновление класса DTO вашей службой внешних данных не приведет к переходу в модель представления. Ваш DTO является частью уровня вашей модели или бизнес-объекта. Его задача - переносить данные между уровнями представления (view и viewmodel) и хранилища (база данных) и выполнять проверку (при необходимости). Обновление внешним (не видимым) сервисом вполне соответствует его роли. Ваш комментарий об одной виртуальной машине в каждом окне или пользовательском контроле не является неправильным - виртуальные машины назначаются для каждого представления, а не для каждого элемента управления (хотя можно повторно использовать один и тот же класс VM для нескольких представлений). У вас должен быть экземпляр DTO, с которым представление связывается на ВМ. В этом и заключается задача виртуальной машины - организовывать, управлять и представлять на рассмотрение требуемые части модели.

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

2) IEditableObject, как упоминалось в другом ответе, является хорошим выбором. Создание резервных копий как службы, так и просмотра данных в вашем DTO не является необходимым, и эффективно увеличивает размер вашего объекта в три раза (при условии, что это тонкая оболочка, какой должна быть, если это DTO). Если вам действительно нужна возможность вернуться к любой версии данных, скажем, потому что вы даете пользователю возможность выбрать, какую версию использовать при возврате, сохраняйте дополнительные данные на вашей виртуальной машине, а не на модели. Я не могу придумать причину, по которой вам нужен вариант, который не включает какие-либо решения для презентации или взаимодействия с пользователем. Возврат данных, управляемый данными, должен быть всегда детерминированным.

3) Снова IEditableObject. Представление не должно уведомлять модель представления; это должно быть в неведении о ВМ (не иметь никаких ссылок). Это ослабит связь между двумя слоями и увеличит гибкость вашего приложения. Обычно я достигаю этого, имея класс контроллера, предназначенный исключительно для обработки представлений. Когда он открывает представление, он создает новый экземпляр виртуальной машины и указывает на него представление DataContext.

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