代码之家  ›  专栏  ›  技术社区  ›  jpfollenius Rob Kennedy

如何避免Delphi中的MVC循环通知?

  •  4
  • jpfollenius Rob Kennedy  · 技术社区  · 15 年前

    我试图在一个小应用程序中使用模型-视图-控制器模式。模型包含一些数据和这样的选择

    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 回复  |  直到 15 年前
        1
  •  9
  •   Tobias Langner    15 年前

    仅在真正更改时通知。

    或者使用标志在更新期间禁用更新。

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

    fchanging是Boolean类型的成员变量

        2
  •  8
  •   Deltics    15 年前

    MVC的一个经典问题——视图中的更改什么时候影响模型,什么时候只影响模型? 反映 模型?

    这应该由控制器来处理——如果它不是由控制器来处理的,那么您实际上没有MVC实现,而是一个带有控制器逻辑的mV,嵌入并分布在模型和视图之间的交互中。

    当用户与视图交互时,视图(TreeView控件)应通知控制器,控制器反过来更新模型。

    模型更新后应通知控制器。

    在这种情况下,控制器已经意识到它正在更新模型,因此可以忽略某些通知,否则它将传递给视图。

    您面临的最大问题是,视图中使用的控件并不是为在MVC实现中使用而设计的。单击TreeView可更改TreeView控件(视图)中的选择。在MVC中,理想情况下,您希望它做的是通知模型(通过控制器)需要将选择更改为单击的项。

    因此,模型选择状态更改,并通知TreeView。任何视图都不应该假设它已经知道它对模型做了什么。

    TreeView选择状态始终只反映模型状态。

    但是,如果不在用户界面控件中做一些工作来创建控制状态和底层模型状态之间的距离,您只需要努力解决问题。

        3
  •  0
  •   ThinkJet    15 年前

    将当前选择存储在视图层中(例如当前选定节点)。 如果控制器要求视图切换到新节点,并且此节点已被选中-不执行任何操作。

    设置属性时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;   
    

    tobias langner的“changing state”方式不好——控制器可以决定选择另一个节点,至少需要

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

    块。