Why is Spring4D's IList<T> OnChanged event not fired when the object changes (while Add and Remove fire the event)?

蓝咒 提交于 2019-12-11 16:47:17

问题


I modified @Stefan Glienkes example from Notify the TObjectList when Object changed to use IList, since I am using interfaced objects in my list. In the event handler, I can handle caAdded and caRemoved events, but caChanged is not signaled.

Is this by design or am I making a mistake somewhere?

This example shows the behavior:

program Project61;

{$APPTYPE CONSOLE}


uses
  Spring,
  Spring.Collections,
  SysUtils;

type
  TNotifyPropertyChangedBase = class(TInterfaceBase, INotifyPropertyChanged)
  private
    fOnPropertyChanged: Event<TPropertyChangedEvent>;
    function GetOnPropertyChanged: IPropertyChangedEvent;
  protected
    procedure PropertyChanged(const propertyName: string);
  end;

  IMyInterface = interface(IInterface)
    ['{D5966D7D-1F4D-4EA8-B196-CB9B39AF446E}']
    function GetName: String;
    procedure SetName(const Value: String);
    property Name: String read GetName write SetName;
  end;

  TMyObject = class(TNotifyPropertyChangedBase, IMyInterface)
  private
    FName: string;
    function GetName: string;
    procedure SetName(const Value: string);
  public
    property Name: string read GetName write SetName;
  end;

  TMain = class
    procedure ListChanged(Sender: TObject; const item: IMyInterface;
      action: TCollectionChangedAction);
  end;

  { TNotifyPropertyChangedBase }

function TNotifyPropertyChangedBase.GetOnPropertyChanged: IPropertyChangedEvent;
begin
  Result := fOnPropertyChanged;
end;

procedure TNotifyPropertyChangedBase.PropertyChanged(
  const propertyName: string);
begin
  fOnPropertyChanged.Invoke(Self,
    TPropertyChangedEventArgs.Create(propertyName) as IPropertyChangedEventArgs);
end;

{ TMyObject }

procedure TMyObject.SetName(const Value: string);
begin
  FName := Value;
  PropertyChanged('Name');
end;

function TMyObject.GetName: string;
begin
  Result := FName;
end;

{ TMain }

procedure TMain.ListChanged(Sender: TObject; const item: IMyInterface;
  action: TCollectionChangedAction);
begin
  case action of
    caAdded:
      Writeln('item added ', item.Name);
    caRemoved, caExtracted:
      Writeln('item removed ', item.Name);
    caChanged:
      Writeln('item changed ', item.Name);
  end;
end;

var
  main: TMain;
  list: IList<IMyInterface>;
  o   : IMyInterface;

begin
  list := TCollections.CreateList<IMyInterface>;
  list.OnChanged.Add(main.ListChanged);
  o := TMyObject.Create;
  o.Name := 'o1';
  list.Add(o);          // triggering caAdded
  o := TMyObject.Create;
  o.Name := 'o2';
  list.Add(o);          // triggering caAdded
  list[1].Name := 'o3'; // not triggering caChanged
  list.Remove(o);       // triggering caRemoved
  Readln;

end.

回答1:


The lists created by TCollections.CreateList, TCollections.CreateObjectList or TCollections.CreateInterfaceList don't support INotifyPropertyChanged.

You see that TCollections.CreateObservableList which I used in my example is contraint to only hold objects as these are typically candidates for implementing property change notification as PODOs are imo usually bad candidates to be used as interfaces.

You can probably still code your own version of that list that accepts interfaces and queries them for INotifyPropertyChanged.



来源:https://stackoverflow.com/questions/56244473/why-is-spring4ds-ilistt-onchanged-event-not-fired-when-the-object-changes-wh

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!