3

I'm using TObjectBindSourceAdapter to use livebindings with an object. One of the properties of the object i'm using with TObjectBindSourceAdapter has an enumerated type, but the field in the adapter is never generated when i use an enumerated type in my object

The Only solution i have found for now is to define the enumerated type as an integer in my object and typecast it. This seems to work fine but you have to keep type casting from and back the enumerated type and integers.

Here is some example code to explain what i mean.

First example which uses the enumerated type that i tried initially and does not seem to work:

 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;

Second example that seems to work by typecasting to integers

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;

I was wondering if someone else had come across this problem and if there is perhaps some other solution to solve this without reverting to integers and keep using the enumerated types. I'm also not sure if my workaround is the common way to do this or not.

4

2 回答 2

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
  • 此转换器转换为的类型
  • 一个 TConverterDescription,其中包含一个匿名过程,用于实际执行转换以及其他一些元数据。

在上面的代码中,该initialization部分调用RegisterConverters,因此只需将单元包含在您的项目中,并且实时绑定框架将在需要将TMyEnum值转换为 时使用转换器string

于 2013-10-22T22:21:06.860 回答
0

将枚举转换为整数并返回确实是适应这种情况的适当方法。比如说……

type
  TMyEnum = (meOne, meTwo, meThree);

正如您已经证明的那样,这些可以转换为整数。当转换为整数时,它使用定义中列出的每个索引。所以...

0 = meOne
1 = meTwo
2 = meThree

你会TMyEnumInteger...

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'
于 2013-06-06T23:21:04.540 回答