我试图按照@ {Stefan Glienke在Why is Spring4D's IList OnChanged event not fired?中建议的实现一个接口的ObservableList。
此版本应实现可观察的接口列表。编译但无法在运行时找到“更改”事件处理程序。 我将某些过程参数从TObject更改为IInterface。 由于基类中的实现,其他一些必须是TObject。
感谢您的帮助。
此示例显示了行为:
program Project62;
{$APPTYPE CONSOLE}
uses
Spring,
Spring.Events,
Spring.Collections,
Spring.Collections.Lists,
SysUtils;
type
// Like TObservableList but for interfaces not classes
TObservableInterfaceList<T: IInterface> = class(TFoldedInterfaceList<T>, INotifyPropertyChanged)
private
fOnPropertyChanged: IEvent<TPropertyChangedEvent>;
function GetOnPropertyChanged: IEvent<TPropertyChangedEvent>;
protected
// Sender must be TObject because of TPropertyChangedEvent
procedure DoItemPropertyChanged(sender: TObject; const eventArgs: IPropertyChangedEventArgs);
procedure DoPropertyChanged(const propertyName: string);
procedure Changed(const value: IInterface; action: TCollectionChangedAction); override;
public
constructor Create; override;
property OnPropertyChanged: IEvent<TPropertyChangedEvent> read GetOnPropertyChanged;
end;
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;
TMyInterfacedObject = 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 ListOfMyInterfaceChanged(Sender: TObject; const item: IMyInterface; action: TCollectionChangedAction);
end;
constructor TObservableInterfaceList<T>.Create;
begin
inherited Create;
fOnPropertyChanged := TPropertyChangedEventImpl.Create;
end;
// Sender must be TObject because of TPropertyChangedEvent
procedure TObservableInterfaceList<T>.DoItemPropertyChanged(sender: TObject; const eventArgs: IPropertyChangedEventArgs);
var
MyInterface: IMyInterface;
begin
if Supports(sender, IMyInterface, MyInterface) then
inherited Changed(MyInterface, caChanged);
end;
procedure TObservableInterfaceList<T>.DoPropertyChanged(const propertyName: string);
begin
if Assigned(fOnPropertyChanged) and fOnPropertyChanged.CanInvoke then
fOnPropertyChanged.Invoke(Self,
TPropertyChangedEventArgs.Create(propertyName) as IPropertyChangedEventArgs);
end;
function TObservableInterfaceList<T>.GetOnPropertyChanged: IEvent<TPropertyChangedEvent>;
begin
Result := fOnPropertyChanged;
end;
procedure TObservableInterfaceList<T>.Changed(const value: IInterface; action: TCollectionChangedAction);
var
notifyPropertyChanged: INotifyPropertyChanged;
propertyChanged: IEvent<TPropertyChangedEvent>; // TPropertyChangedEvent = procedure(Sender: TObject; const EventArgs: IPropertyChangedEventArgs) of object;
begin
if Supports(value, INotifyPropertyChanged, notifyPropertyChanged) then
begin
propertyChanged := notifyPropertyChanged.OnPropertyChanged;
case action of
caAdded:
propertyChanged.Add(DoItemPropertyChanged);
caRemoved, caExtracted:
propertyChanged.Remove(DoItemPropertyChanged);
end;
end;
inherited Changed(value, action);
DoPropertyChanged('Count');
end;
function TNotifyPropertyChangedBase.GetOnPropertyChanged: IPropertyChangedEvent;
begin
Result := fOnPropertyChanged;
end;
procedure TNotifyPropertyChangedBase.PropertyChanged(const propertyName: string);
begin
fOnPropertyChanged.Invoke(Self, TPropertyChangedEventArgs.Create(propertyName) as IPropertyChangedEventArgs);
end;
procedure TMyInterfacedObject.SetName(const Value: string);
begin
FName := Value;
PropertyChanged('Name');
end;
function TMyInterfacedObject.GetName: string;
begin
Result := FName;
end;
procedure TMain.ListOfMyInterfaceChanged(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;
iListOfMyInterface: IList<IMyInterface>;
MyInterfacedObject: TMyInterfacedObject;
begin
iListOfMyInterface := TCollections.CreateInterfaceList<IMyInterface>;
iListOfMyInterface.OnChanged.Add(main.ListOfMyInterfaceChanged);
MyInterfacedObject := TMyInterfacedObject.Create;
MyInterfacedObject.Name := 'MyInterfacedObject';
iListOfMyInterface.Add(MyInterfacedObject);
iListOfMyInterface.first.Name := 'MyInterfacedObject hit the change event';
Readln;
end.
答案 0 :(得分:1)
因为您从未在代码中创建TObservableInterfaceList<T>
,但是:
iListOfMyInterface := TCollections.CreateInterfaceList<IMyInterface>;
正确:
iListOfMyInterface := TObservableInterfaceList<IMyInterface>.Create;
您对DoItemPropertyChanged
的实现也存在缺陷。您在此处指的是一种特殊的接口类型,但实际上您必须将发件人向下传递为T,因为这是列表元素类型。
我将考虑为2.0开箱即用。