问题
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