Как избежать циркулярных уведомлений в MVC в Delphi? - PullRequest
4 голосов
/ 15 декабря 2009

Я пытаюсь использовать шаблон Model-View-Controller в небольшом приложении. Модель содержит некоторые данные и выборку, подобную этой

TModelSelection = record
  CurrentItem : TItem;
end;  

TModel = class
public
  property Items : TList <TItem>;
  property Selection : TModelSelection;
  property Subject : TSubject <TModel>;    // Observer pattern
end;

Теперь у меня есть дерево, которое наблюдает за моделью. Если пользователь выбирает элемент в виде дерева, выбор модели должен измениться.

Проблема в том, что у меня возникают проблемы с круговыми уведомлениями об изменениях: я меняю выбор модели в событии OnChange в виде дерева. Это заставляет древовидное представление обновлять свой выбор (поскольку выбор может быть также изменен другими частями приложения), что снова вызывает событие OnChange и т. Д.

Как мне избежать этой проблемы?

Ответы [ 3 ]

9 голосов
/ 15 декабря 2009

уведомлять только об истинных изменениях.

Или используйте флаг, чтобы отключить обновления во время обновлений.

procedure OnChange(...)
begin
  if FChanging = false then
  begin
    FChanging:=true;
    ... do updates
    FChanging:=false;
  end;
end;

с переменной FChanging типа Boolean

8 голосов
/ 15 декабря 2009

Классическая проблема с MVC - когда изменение вида влияет на модель и когда оно просто отражает модель?

Это должно решаться контроллером - если он не обрабатывается контроллером, то у вас действительно нет реализации MVC, а просто MV с логикой контроллера, встроенной и распределенной по взаимодействиям между моделью и Просмотр.

Когда пользователь взаимодействует с представлением, представление (древовидное управление) должно уведомить контроллер, который, в свою очередь, обновляет модель.

Когда Модель обновляется, она должна уведомить Контроллер.

В этом сценарии Контроллер уже знает, что он обновляет Модель, и поэтому может игнорировать определенные уведомления, которые он в противном случае передал бы в Представление.

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

Таким образом, состояние выбора модели изменяется, и Treeview уведомляется. Ни один View не должен предполагать, что он уже знает, что он делает с Моделью.

Состояние выбора Treeview всегда всегда является отражением состояния модели.

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

0 голосов
/ 16 декабря 2009

Сохранить текущий выбор в слое вида (например, текущий выбранный узел). Если контроллер запросил просмотр для переключения на новый узел, и этот узел уже выбран - ничего не делать.

Стандартное поведение компонентов delphi, когда свойство установлено:

type TSomeClass = class
  private 
    FSomeValue : TSomeType; 
  protected
    procedure SetSomeProperety(const AValue: TSomeType);
  public
    property SomeProperty : TSomeType read FValue write SetSomeProperty; 
end;

procedure TSomeClass.SetSomeProperety(const AValue: TSomeType);
begin
  if(AValue = FValue) then exit;
  FValue := AValue;
  // do other actions to reflect change
end;   

Путь с «Изменением состояния» Тобиаса Лангнера не годится - Контроллер может решить выбрать другой узел и, по крайней мере, потребовать

try 
  ... 
finally 
  FChanging := false; 
end; 

блок.

...