Delphi Livebinding объект и выпадающий список или переключатели
Я определил последующий блок для бизнес-логики
unit Models.Person;
interface
Type
TPersonGender = (pgUndefined, pgMale, pgFemale, pgNotApplicable);
TSexOfPerson = class(TPersistent)
private
FGender : TPersonGender;
protected
function GetDescription : string;
function GetCode : string;
function GetIndex : integer;
public
constructor Create; overload;
constructor Create(const aValue : TGenderPerson); overload;
procedure Assign(Source: TPersistent); override;
property Gender : TGenderPerson read FGender write FGender;
property Description : string read GetDescription;
property Code : string read GetCode;
property Index : integer read GetIndex;
end;
TPerson = class(TPersistent)
private
FSex : TSexOfPerson;
FName : string;
FSurName : string;
FAddress : string;
protected
function GetSex : TPersonGender;
procedure SetSex(aGender : TPersonGender);
public
constructor Create; overload;
constructor Create(const aValue : TPerson); overload;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
property Name : string read FName write FName;
property SurName : string read FSurName write FSurName;
property Address : string read FAddress write FAddress;
property Sex : TPersonGender read GetSex write SetSex
end;
implementation
{ TSexOfPerson }
constructor TSexOfPerson.Create;
begin
inherited Create;
FGender := pgUndefined;
end;
constructor TSexOfPerson.Create(const aValue : TPersonGender);
begin
inherited Create;
FGender := aValue
end;
procedure TSexOfPerson.Assign(Source: TPersistent);
begin
if Source is TSexOfPerson then
FGender := TSexOfPerson(Source).Gender
else
inherited Assign(Source)
end;
function TSexOfPerson.GetDescription;
begin
case FGender of
pgUndefined : Result := '<Undefined>';
pgMale : Result := 'Male';
pgFemale : Result := 'Female';
pgNotApplicable : Result := '<Not applicable>';
end
end;
function TSexOfPerson.GetIndex;
begin
Result := Ord(FGender)
end;
function TSexOfPerson.GetCodice;
begin
case FGender of
pgUndefined : Result := '';
pgMale : Result := 'M';
pgFemale : Result := 'F';
pgNotApplicable : Result := 'N'
end
end;
{ TPerson }
constructor TPerson.Create;
begin
inherited Create;
FSex := TSexOfPerson.Create(pgUndefined)
end;
constructor TPerson.Create(const aValue : TPerson);
begin
inherited Create;
FSex := TSexOfPerson.Create(aValue)
end;
destructor TPerson.Destroy;
begin
FSex.Free;
inherited Destroy
end;
procedure TPerson.Assign(Source: TPersistent);
begin
if Source is TPerson then
begin
FName := TPerson(Source).Name;
FSurName := TPerson(Source).SurName;
FAddress := TPerson(Source).Address;
FSex.Gender := TPerson(Source).Sex;
end
else
inherited Assign(Source)
end;
function GetSex : TPersonGender;
begin
Result := FSex.Gender
end;
procedure SetSex(aGender : TPersonGender);
begin
if FSex.Gender <> aGender then
FSex.Gender := aGender
end;
end.
Теперь я разработаю форму для редактирования TPerson с тремя TEdit и TCombobox для выбора пола.
Как я могу использовать двунаправленный livebinding для TCombobox?
2 ответа
Принимая во внимание, что живые привязки между несовместимыми классами и элементами управления не просты с Delphi, чтобы упростить, я счел целесообразным изменить класс TPerson следующим образом:
TPerson = class(TPersistent)
private
FSex : TSexOfPerson;
FName : string;
FSurName : string;
FAddress : string;
protected
function GetSex : TPersonGender;
procedure SetSex(aGender : TPersonGender);
public
constructor Create; overload;
constructor Create(const aValue : TPerson); overload;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
property Name : string read FName write FName;
property SurName : string read FSurName write FSurName;
property Address : string read FAddress write FAddress;
property Sex : integer read GetSex write SetSex
end;
implementation
...
function TPerson.GetSex : integer;
begin
Result := FSex.Index
end;
procedure TPerson.SetSex (aValue : integer);
begin
if FSex.Integer <> aValue then
case aValue of
0 : FSex.MtsSesso := pgUndefined;
1 : FSex.MtsSesso := pgMale;
2 : FSex.MtsSesso := pgFemale;
3 : FSex.MtsSesso := pgNotApplicable;
end;
end;
procedure TPerson.Assign(Source: TPersistent);
begin
if Source is TPerson then
begin
FName := TPerson(Source).Name;
FSurName := TPerson(Source).SurName;
FAddress := TPerson(Source).Address;
case TPerson(Source).Sex of
0 : FSex.MtsSesso := pgUndefined;
1 : FSex.MtsSesso := pgMale;
2 : FSex.MtsSesso := pgFemale;
3 : FSex.MtsSesso := pgNotApplicable;
end;
end
else
inherited Assign(Source)
end;
...
Далее я определил адаптер для TPerson:
type
TPersonsAdapter = class(TListBindSourceAdapter<TPerson>)
public
constructor Create(AOwner: TComponent); override;
end;
procedure Register;
...
constructor TPersonsAdapter.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
//load Persons list
SetList(LoadPersons)
end;
procedure Register;
begin
RegisterComponents('CustomAdapters', [TPersonsAdapter]);
end;
В форме я удалил TBindingList (BindingList1), TAdapterBindSource (PersonABS), TPersonsAdapter (PersonsAdapter) и 4 TRadioButton;
чем установить
PersonABS.Adapter := PersonsAdapter;
PersonABS.OnCreateAdapter := PersonABSCreateAdapter;
procedure TForm1.PersonABSCreateAdapter(Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter);
begin
ABindSourceAdapter := TObjectBindSourceAdapter<TPerson>.Create(PersonABS, CurrentPerson, False);
ABindSourceAdapter.AutoPost := True;
end;
On BindingList1 component, create 4 TLinkPropertyToField one for each radiobutton and set the following as:
LinkPropertyToField1.Component := RadioButton1;
LinkPropertyToField1.ComponentProperty := IsChecked
LinkPropertyToField1.CustomFormat := 'IfThen(%s=0, True, False)';
LinkPropertyToField1.DataSource := PersonABS;
LinkPropertyToField1.FieldName := 'Sex';
LinkPropertyToField2.Component := RadioButton2;
LinkPropertyToField2.ComponentProperty := IsChecked
LinkPropertyToField2.CustomFormat := 'IfThen(%s=1, True, False)';
LinkPropertyToField2.DataSource := PersonABS;
LinkPropertyToField2.FieldName := 'Sex';
LinkPropertyToField3.Component := RadioButton3;
LinkPropertyToField3.ComponentProperty := IsChecked
LinkPropertyToField3.CustomFormat := 'IfThen(%s=2, True, False)';
LinkPropertyToField3.DataSource := PersonABS;
LinkPropertyToField3.FieldName := 'Sex';
LinkPropertyToField4.Component := RadioButton4;
LinkPropertyToField4.ComponentProperty := IsChecked
LinkPropertyToField4.CustomFormat := 'IfThen(%s=3, True, False)';
LinkPropertyToField4.DataSource := PersonABS;
LinkPropertyToField4.FieldName := 'Sex';
На каждом TRadioButton установите событие onClick следующим образом:
procedure TForm1.RadioButton1Click(Sender: TObject);
begin
if not TRadioButton(Sender).IsChecked then
CurrentPerson.Sex := Ord(pgUndefined)
end;
procedure TForm1.RadioButton2Click(Sender: TObject);
begin
if not TRadioButton(Sender).IsChecked then
CurrentPerson.Sex := Ord(pgMale)
end;
procedure TForm1.RadioButton3Click(Sender: TObject);
begin
if not TRadioButton(Sender).IsChecked then
CurrentPerson.Sex := Ord(pgFemale)
end;
procedure TForm1.RadioButton4Click(Sender: TObject);
begin
if not TRadioButton(Sender).IsChecked then
CurrentPerson.Sex := Ord(pgNotApplicable)
end;
это все.
Я надеюсь, что решение является достаточно надежным и его легче повторить.
Если вы используете TComboBox вместо TRadioButtons, мы поступаем следующим образом. Я предпочитаю создавать адаптер для класса TSexOfPerson:
type
TSexOfPersonsAdapter = class(TListBindSourceAdapter<TSexOfPerson>)
public
constructor Create(AOwner: TComponent); override;
end;
procedure Register;
...
constructor TSexOfPersonsAdapter.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
//load Sex Persons list
SetList(LoadSexOfPerson)
end;
procedure Register;
begin
RegisterComponents('CustomAdapters', [TSexOfPersonsAdapter]);
end;
function LoadSexOfperson: TList<TSexOfPerson>;
begin
Result := TObjectList<TSexOfPerson>.Create;
Result.Add(TSexOfPerson.Create(pgUndefined));
Result.Add(TSexOfPerson.Create(pgMale));
Result.Add(TSexOfPerson.Create(pgFemale));
Result.Add(TSexOfPerson.Create(pgNotApplicable));
end;
В форме перетащите TBindingList (BindingList1), TAdapterBindSource (PersonABS), TPersonsAdapter (PersonsAdapter1), TAdapterBindSource (SexOfPersonABS), TSexOfPersonsAdapter (SexOfPersonsAdapter1) и ComomBox1.
Чем установить
SexOfPersonABS.Adapter = SexOfPersonsAdapter1;
PersonABS.Adapter = PersonsAdapter1;
PersonABS.OnCreateAdapter = PersonABSCreateAdapter;
procedure TForm1.PersonABSCreateAdapter(Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter);
begin
ABindSourceAdapter := TObjectBindSourceAdapter<TPerson>.Create(PersonABS, CurrentPerson, False);
ABindSourceAdapter.AutoPost := True;
end;
Откройте конструктор живых привязок и свяжите SexOfPersonABS.Description с ComboBox1.Item.Text и SexOfPersonABS.Index с ComboBox1.Item.LookupData, который создаст TLinkFillPropertyToField (LinkFillControlToField1); также свяжите свойство PersonABS.Sex с ComboBox1.SelectedValue.
Установите следующее:
LinkFillControlToField1.Control = ComboBox1;
LinkFillControlToField1.DataSource = PersonABS;
LinkFillControlToField1.FieldName = 'Sex';
LinkFillControlToField1.FillDataSource = SexOfPersonABS;
LinkFillControlToField1.FillDisplayFieldName = 'Description';
LinkFillControlToField1.FillValueFieldName = 'Index';
На ComboBox1 установите OnChange следующим образом
procedure TForm1.ComboBox1Change(Sender: TObject);
var
aValue : TValue;
begin
aValue := LinkFillControlToField1.BindList.GetSelectedValue;
case aValue.AsInteger of
Ord(pgUndefined) : CurrentPerson.Sex := Ord(pgUndefined);
Ord(pgMale) : CurrentPerson.Sex := Ord(pgMale);
Ord(pgFemale) : CurrentPerson.Sex := Ord(pgFemale);
Ord(pgNotApplicable) : CurrentPerson.Sex := Ord(pgNotApplicable);
end
end;
Это все.