Почему событие IList <T>OnChanged в Spring4D не вызывается при изменении объекта (в то время как Add и Remove запускают событие)? - PullRequest
0 голосов
/ 21 мая 2019

Я изменил пример @Stefan Glienkes из Уведомить TObjectList, когда Object изменил , чтобы использовать IList, так как я использую сопряженные объекты в моем списке.В обработчике событий я могу обрабатывать события caAdded и caRemoved, но caChanged не сигнализируется.

Это из-за замысла или я где-то ошибаюсь?

В этом примере показано поведение:

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 Ответ

2 голосов
/ 21 мая 2019

Списки, созданные TCollections.CreateList, TCollections.CreateObjectList или TCollections.CreateInterfaceList, не поддерживают INotifyPropertyChanged.

Вы видите, что TCollections.CreateObservableList, который я использовал в моем примере, является противопоказанием для хранения только объектов, поскольку они обычно являются кандидатами для реализации уведомления об изменении свойств, поскольку PODO, как правило, являются плохими кандидатами для использования в качестве интерфейсов.

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

...