使用 TListView 绑定对象
Binding an object with a TListView
我最近发现了 Data Bindings
,并关注了 this great tutorial about data binding
and Delphi。我让它与 TEdit
一起工作,但现在我有一个 TObjectList
并且我实现了绑定它们,但它只能以一种方式工作。当我修改 TObjectList
时,它会更改 ListView
,但是当我修改 ListView
时:它不会更改 TOBjectList
.
这是我的代码:
// When I change an Item of my ListView
procedure TForm1.ListView1Change(Sender: TObject; Item: TListItem;
Change: TItemChange);
begin
TBindings.Notify(Sender, 'Items.Item[' + IntToStr(Item.Index) + '].Caption');
end;
// When I add a new item to my TListView, and I want that to be bound with my ListView
itemAdd := ListView1.Items.Add;
Item.Bind('id', ListView1, 'Items.Item[' + IntToStr(ListView1.Items.Count-1) + '].Caption');
// The TBoundObject Class. Every class thatI want to bind with UI, inherits from this class
unit U_TBoundObject;
interface
uses
Generics.Collections, System.Bindings.Expression, System.Bindings.Helper;
type
TBoundObject = class
protected
type
TExpressionList = TObjectList<TBindingExpression>;
private
FBindings: TExpressionList;
protected
procedure Notify(const APropertyName: string = '');
property Bindings: TExpressionList read FBindings;
public
constructor Create; virtual;
destructor Destroy; override;
procedure Bind(const AProperty: string; const ABindToObject: TObject;
const ABindToProperty: string; const ACreateOptions:
TBindings.TCreateOptions = [coNotifyOutput, coEvaluate]);
procedure ClearBindings;
end;
implementation
constructor TBoundObject.Create;
begin
inherited;
FBindings := TExpressionList.Create(false {AOwnsObjects});
end;
destructor TBoundObject.Destroy;
begin
ClearBindings;
FBindings.Free;
inherited;
end;
procedure TBoundObject.ClearBindings;
var
i: TBindingExpression;
begin
for i in FBindings do
TBindings.RemoveBinding(i);
FBindings.Clear;
end;
procedure TBoundObject.Notify(const APropertyName: string);
begin
TBindings.Notify(Self, APropertyName);
end;
procedure TBoundObject.Bind(const AProperty: string;
const ABindToObject: TObject; const ABindToProperty: string;
const ACreateOptions: TBindings.TCreateOptions);
begin
// From source to dest
FBindings.Add(TBindings.CreateManagedBinding(
{ inputs }
[TBindings.CreateAssociationScope([Associate(Self, 'src')])],
'src.' + AProperty,
{ outputs }
[TBindings.CreateAssociationScope([Associate(ABindToObject, 'dst')])],
'dst.' + ABindToProperty,
nil, nil, ACreateOptions));
// From dest to source
FBindings.Add(TBindings.CreateManagedBinding(
{ inputs }
[TBindings.CreateAssociationScope([Associate(ABindToObject, 'src')])],
'src.' + ABindToProperty,
{ outputs }
[TBindings.CreateAssociationScope([Associate(Self, 'dst')])],
'dst.' + AProperty,
nil, nil, ACreateOptions));
end;
end.
我知道你想做什么,但你并没有真正去做。
本质上,您试图绑定两个对象的属性,但您将子属性(属性 的属性)视为属性。你说它是单向的,但对我来说不是。
通过直接(而不是间接)处理对象变得容易得多。
这就是我添加和关联相关对象的方式
procedure TForm2.SpeedButtonAddClick(Sender: TObject);
var
ItemAdd : TListItem;
Item : TFeature;
begin
Item := TFeature.Create;
fObjectList.Add( Item );
ItemAdd := ListView1.Items.Add;
Item.Bind('id', ItemAdd, 'Caption');
end;
这是对象更改的代码
procedure TFeature.SetID(const Value: string);
begin
if fID <> Value then // prevent an infinite loop
begin
fID := Value;
TBindings.Notify( self, 'id' );
end;
end;
(测试是为了防止两个对象不断的互相更新)
这是 ItemView 更改的代码
procedure TForm2.ListView1Change(Sender: TObject; Item: TListItem;
Change: TItemChange);
begin
TBindings.Notify(Item, 'Caption');
end;
我已经测试过了,它可以双向工作。
我最近发现了 Data Bindings
,并关注了 this great tutorial about data binding
and Delphi。我让它与 TEdit
一起工作,但现在我有一个 TObjectList
并且我实现了绑定它们,但它只能以一种方式工作。当我修改 TObjectList
时,它会更改 ListView
,但是当我修改 ListView
时:它不会更改 TOBjectList
.
这是我的代码:
// When I change an Item of my ListView
procedure TForm1.ListView1Change(Sender: TObject; Item: TListItem;
Change: TItemChange);
begin
TBindings.Notify(Sender, 'Items.Item[' + IntToStr(Item.Index) + '].Caption');
end;
// When I add a new item to my TListView, and I want that to be bound with my ListView
itemAdd := ListView1.Items.Add;
Item.Bind('id', ListView1, 'Items.Item[' + IntToStr(ListView1.Items.Count-1) + '].Caption');
// The TBoundObject Class. Every class thatI want to bind with UI, inherits from this class
unit U_TBoundObject;
interface
uses
Generics.Collections, System.Bindings.Expression, System.Bindings.Helper;
type
TBoundObject = class
protected
type
TExpressionList = TObjectList<TBindingExpression>;
private
FBindings: TExpressionList;
protected
procedure Notify(const APropertyName: string = '');
property Bindings: TExpressionList read FBindings;
public
constructor Create; virtual;
destructor Destroy; override;
procedure Bind(const AProperty: string; const ABindToObject: TObject;
const ABindToProperty: string; const ACreateOptions:
TBindings.TCreateOptions = [coNotifyOutput, coEvaluate]);
procedure ClearBindings;
end;
implementation
constructor TBoundObject.Create;
begin
inherited;
FBindings := TExpressionList.Create(false {AOwnsObjects});
end;
destructor TBoundObject.Destroy;
begin
ClearBindings;
FBindings.Free;
inherited;
end;
procedure TBoundObject.ClearBindings;
var
i: TBindingExpression;
begin
for i in FBindings do
TBindings.RemoveBinding(i);
FBindings.Clear;
end;
procedure TBoundObject.Notify(const APropertyName: string);
begin
TBindings.Notify(Self, APropertyName);
end;
procedure TBoundObject.Bind(const AProperty: string;
const ABindToObject: TObject; const ABindToProperty: string;
const ACreateOptions: TBindings.TCreateOptions);
begin
// From source to dest
FBindings.Add(TBindings.CreateManagedBinding(
{ inputs }
[TBindings.CreateAssociationScope([Associate(Self, 'src')])],
'src.' + AProperty,
{ outputs }
[TBindings.CreateAssociationScope([Associate(ABindToObject, 'dst')])],
'dst.' + ABindToProperty,
nil, nil, ACreateOptions));
// From dest to source
FBindings.Add(TBindings.CreateManagedBinding(
{ inputs }
[TBindings.CreateAssociationScope([Associate(ABindToObject, 'src')])],
'src.' + ABindToProperty,
{ outputs }
[TBindings.CreateAssociationScope([Associate(Self, 'dst')])],
'dst.' + AProperty,
nil, nil, ACreateOptions));
end;
end.
我知道你想做什么,但你并没有真正去做。
本质上,您试图绑定两个对象的属性,但您将子属性(属性 的属性)视为属性。你说它是单向的,但对我来说不是。
通过直接(而不是间接)处理对象变得容易得多。
这就是我添加和关联相关对象的方式
procedure TForm2.SpeedButtonAddClick(Sender: TObject);
var
ItemAdd : TListItem;
Item : TFeature;
begin
Item := TFeature.Create;
fObjectList.Add( Item );
ItemAdd := ListView1.Items.Add;
Item.Bind('id', ItemAdd, 'Caption');
end;
这是对象更改的代码
procedure TFeature.SetID(const Value: string);
begin
if fID <> Value then // prevent an infinite loop
begin
fID := Value;
TBindings.Notify( self, 'id' );
end;
end;
(测试是为了防止两个对象不断的互相更新)
这是 ItemView 更改的代码
procedure TForm2.ListView1Change(Sender: TObject; Item: TListItem;
Change: TItemChange);
begin
TBindings.Notify(Item, 'Caption');
end;
我已经测试过了,它可以双向工作。