如何(正确)使用带有livebindings的枚举类型(TObjectBindSourceAdapter)

时间:2013-06-05 15:05:30

标签: delphi enums livebindings

我使用TObjectBindSourceAdapter与对象一起使用livebindings。 与TObjectBindSourceAdapter一起使用的对象的一个​​属性具有枚举类型,但是当我在对象中使用枚举类型时,从不生成适配器中的字段

我现在发现的唯一解决方案是将枚举类型定义为我的对象中的整数并对其进行类型转换。这似乎工作正常,但你必须保持类型转换和枚举类型和整数。

以下是一些解释我的意思的示例代码。

第一个使用我最初尝试过但似乎不起作用的枚举类型的例子:

 uses Data.Bind.ObjectScope;

 Type
   TMyEnumtype = (meOne, meTwo, meThree);

   TMyObject = class
     public
       MyEnumType: TMyEnumtype;
  end;

procedure TForm9.But1Click(Sender: TObject);
var
  MyObject: TMyObject;
  aBindSourceAdapter: TBindSourceAdapter;
begin
  MyObject := TMyObject.Create;
  MyObject.MyEnumType := meTwo;
  aBindSourceAdapter := TObjectBindSourceAdapter<TMyObject>.Create(nil, MyObject, False);
  if aBindSourceAdapter.FindField('MyEnumType') <> nil then
    ShowMessage('MyEnumType found')
  else
    showmessage('MyEnumType not found');
  FreeAndNil(MyObject);
  FreeAndNil(aBindSourceAdapter);
end;

似乎通过类型转换为整数的第二个例子

uses Data.Bind.ObjectScope;

Type
  TMyEnumtype = (meOne, meTwo, meThree);

  TMyObject = class
    public
      MyEnumType: integer;
  end;

procedure TForm9.But1Click(Sender: TObject);
var
  MyObject: TMyObject;
  aBindSourceAdapter: TBindSourceAdapter;
  aEnumType : TMyEnumtype;
begin
  MyObject := TMyObject.Create;
  MyObject.MyEnumType := Integer(meTwo);
  aBindSourceAdapter := TObjectBindSourceAdapter<TMyObject>.Create(nil, MyObject, False);
  if aBindSourceAdapter.FindField('MyEnumType') <> nil then
    ShowMessage('MyEnumType found')
  else
    showmessage('MyEnumType not found');

  aEnumType := TMyEnumtype(aBindSourceAdapter.FindField('MyEnumType').GetTValue.AsInteger);

  if aEnumType =  meTwo then
    showmessage('meTwo');

  FreeAndNil(MyObject);
  FreeAndNil(aBindSourceAdapter);
end;

我想知道是否有其他人遇到过这个问题,是否有其他解决方案可以解决这个问题,而不需要恢复整数并继续使用枚举类型。我也不确定我的解决方法是否是常见的方法。

2 个答案:

答案 0 :(得分:2)

我认为最好的方法是注册转换器。事实证明这很简单,但只有在深入了解VCL源代码之后。我没有找到任何有用的文档。但就是这样。

unit MyConverters;

interface

uses System.Rtti, System.Bindings.Outputs;

type
  TMyEnum = (Value1, Value2, Value3);

implementation

procedure RegisterConverters;
begin
  TValueRefConverterFactory.RegisterConversion(TypeInfo(TMyEnum), TypeInfo(string),
    TConverterDescription.Create(
      procedure(const InValue: TValue; var OutValue: TValue)
      var
        MyEnum: TMyEnum;
        S: string;
      begin
        MyEnum := InValue.AsType<TMyEnum>;
        case MyEnum of
          Value1:  S := 'First Value';
          Value2:  S := 'Second Value';
          Value3:  S := 'Third Value';
          else     S := 'Other';
        end;
        OutValue := TValue.From<string>(S);
      end,
      'TMyEnumToString',
      'TMyEnumToString',
      '', // TODO what is the AUnitName param used for?
      True, // TODO what is ADefaultEnabled used for?  What does it mean?
      'Converts a TMyEnum value to a string',
      nil)
  );
end;

initialization
  RegisterConverters;
end.

简而言之,您致电TValueRefConverterFactor.RegisterConversion()并传入:

  • 此转换器转换的类型 FROM
  • 此转换器转换的类型 TO
  • 包含实际执行转换的匿名过程以及其他一些元数据的TConverterDescription。

在上面的代码中,initialization部分调用了RegisterConverters,因此所有必要的是将单元包含在项目中,并且实时绑定框架将在需要转换时使用转换器TMyEnum的{​​{1}}值。

答案 1 :(得分:0)

将枚举作为整数和背面进行转换实际上是适合这种情况的适当方法。比方说吧......

type
  TMyEnum = (meOne, meTwo, meThree);

正如您已经演示的那样,这些可以作为整数进行转换。当作为整数进行转换时,它使用索引,其中每个索引都在定义中列出。所以......

0 = meOne
1 = meTwo
2 = meThree

您可以将TMyEnum转换为Integer,如...

Something := Integer(MyEnumValue);

然后把它丢回......

Something := TMyEnum(MyIntegerValue);

这被广泛用于解决您的确切问题,我自己一直使用它。我很久以前就研究了同样的场景,并得出结论,这是实现这一目的的唯一方法 - 除非你想做一些更复杂的转换,比如使用字符串......

function MyEnumToStr(const MyEnum: TMyEnum): String;
begin
  case MyEnum of
    meOne: Result:= 'meOne';
    meTwo: Result:= 'meTwo';
    meThree: Result:= 'meThree';
  end;
end;

function StrToMyEnum(const Str: String): TMyEnum;
var
  S: String;
begin
  S:= UpperCase(Str);
  if S = 'MEONE' then Result:= meOne
  else if S = 'METWO' then Result:= meTwo
  else if S = 'METHREE' then Result:= meThree;
end;

(我确信还有其他方法可以if使用StrToMyEnum语句

以这种方式使用字符串可以使事情更具可读性。一个更现实世界的例子......

type
  TCustomerType = (cmRetail, cmWholesale, cmDesigner);

其中...

cmRetail = 'Retail Customer'
cmWholesale = 'Wholesale Customer'
cmDesigner = 'Designer Customer'