CancelEdit, CancelViewModel и HasDirtyModel во вложенных элементах управления Catel

У меня есть окно, содержащее вложенный элемент управления NC1, который содержит 3 экземпляра вложенного элемента управления NC2. У меня есть кнопка «сброс» на NC1, которая должна сбрасывать значения NC1 и всех трех NC2 в NC1.

Я пробовал несколько реализаций кнопки «Сброс», но они не увенчались успехом. Во всех случаях HasDirtyModel остается истинным даже при сбросе данных.

Я попытался явно вызвать ((IEditableObject)nc2).CancelEdit() для всех трех экземпляров NC2 и ((IEditableObject)nc1).CancelEdit(). Хотя это полностью сбрасывает, выполнение только CancelEdit на NC1 не приводило к сбросу моделей NC2. (Модель представления NC1 имеет свойство с [Model] и [Expose("NC2s")], которое является списком в модели NC1.

Вызов CancelViewModel() также сбрасывает данные, но все равно оставляет значение HasDirtyModel равным true.

Все модели происходят от ModelBase. Что мне делать, чтобы HasDirtyModel стал ложным.

Эта проблема связана с приложением WPF, использующим Catel 3.9.


person SOHO Developer    schedule 18.04.2014    source источник


Ответы (2)


Catel не поддерживает комбинацию Cancel и HasDirtyModels. Внутри Catel подписывается на модели с помощью INotifyPropertyChanged. Как только возникают события и значения различаются, модель считается грязной.

К сожалению, модель может реализовать IEditableObject без возможности подписки из внешнего мира. Это делает невозможным (или, по крайней мере, очень затратным по производительности) проверку того, откатывается ли модель каждый раз. Это можно «исправить», только отслеживая полностью клонированный граф объектов и сравнивая, полностью ли текущий граф объектов равен исходному.

Это потребует полного клонирования графа для каждой модели в модели представления, что просто слишком дорого для производительности (особенно с учетом платформ ARM).

Одним из простых решений является самостоятельное отслеживание состояния сброса. Вы единственный человек, который знает, когда вызывается CancelEdit. Это означает, что вы можете установить _hasDirtyModels на своей виртуальной машине и сбросить его при вызове CancelEdit.

person Geert van Horrik    schedule 19.04.2014
comment
Я понимаю, почему вы не поддерживаете CancelEdit и HasDirtyModel, но я ожидал, что CancelViewModel будет иметь такую ​​поддержку. Таким образом, я могу переопределить метод Cancel() в IAdvancedEditableObject (у меня нет имени перед собой), чтобы узнать, когда обновление будет отменено, но какова минимальная работа, чтобы узнать, когда что-то в модели было изменено? - person SOHO Developer; 19.04.2014
comment
Вы знаете, что модель изменилась, если она 1) реализует INotifyPropertyChanged и 2) вы подписываетесь на нее и устанавливаете флаг _isDirty в true. - person Geert van Horrik; 19.04.2014
comment
Согласен, однако не похоже, что ModelBase реализует INotfyPropertyChanged. Я прихожу к выводу, что Модель должна будет зарегистрироваться для изменения каждого свойства в ней, а затем использовать первое изменение, чтобы указать, что модель изменилась. У фреймворка уже есть такой код, который я могу использовать? - person SOHO Developer; 19.04.2014
comment
Конечно, ModelBase реализует INotifyPropertyChanged. Один класс, на который вы, возможно, захотите взглянуть, — это ChangeNotificationWrapper, который использует слабые события (тогда вы не вводите утечки памяти) для наблюдения за объектом. См. определение IModel, которое реализует ModelBase: github.com/Catel/Catel/blob/ - person Geert van Horrik; 19.04.2014
comment
Если вы хотите узнать, как работает ChangeNotificationWrapper, взгляните на catelproject. atlassian.net/wiki/display/CTL/ - person Geert van Horrik; 19.04.2014

Таким образом, простым (надеюсь) решением является создание свойства IsModelDirty на уровне модели. Избегайте IsDirty, потому что его нельзя переопределить, и установки его в false достаточно, чтобы снова сделать модель грязной (т. е. IsDirty становится истинным). Переопределите OnPropertyChanged в модели и установите в ней IsModelDirty true. В моем случае нет необходимости гарантировать, что изменяемое свойство НЕ является IsDirty из-за моего потока управления. Фреймворк уже установил его в True, и ни он, ни я больше никогда не устанавливали его в False. В моем конструкторе модели я установил для LeanAndMeanModel значение true. Я переопределяю OnBeginEdit, OnEndEdit и OnCancelEdit в модели. Код для каждого из них приведен ниже.

/// <inheritdoc />
protected override void OnBeginEdit (System.ComponentModel.BeginEditEventArgs e)
{
  base.OnBeginEdit(e);
  IsModelDirty = false;
  LeanAndMeanModel = false;
}/* method TLModelBase OnBeginEdit */

/// <inheritdoc />
protected override void OnCancelEdit (System.ComponentModel.EditEventArgs e)
{
  LeanAndMeanModel = true;
  base.OnCancelEdit(e);
  IsModelDirty = false;
  LeanAndMeanModel = false;
}/* method TLModelBase OnCancelEdit */

/// <inheritdoc />
protected override void OnEndEdit (System.ComponentModel.EditEventArgs e)
{
  LeanAndMeanModel = true;
  base.OnEndEdit(e);
  IsModelDirty = false;
  LeanAndMeanModel = false;
}/* method TLModelBase OnEndEdit */

Наконец, переопределите HasDirtyModel для доступа к IsDirtyFlag для каждой модели, зарегистрированной для ViewModel, с помощью GetAllModels().

person SOHO Developer    schedule 22.04.2014