Linking object/TValue to a control, VCL to FireMonkey

In this post, Tag properties and using Rtti.TValue data property as an alternative in FireMonkey / FMX.

Click / Select… now what?

One common challenge we face as developers is that the user clicks on something, we now need to find the object that is required to do the next task based on the item selected.

Sometimes this is from a dataset linked to the control and it may be taken care of for us, other times, we may need to find a specific object that then has the data we need.

Most of us have done it at some time….

Yes… that naughty little trick of using the tag property of a TComponent to store a pointer to an instance of an object that you want a quick way of reaching.

I remember doing this in a POS system where buttons that represented different stock items were linked to dynamically created screens. I also remember often using the TListView and thankfully, the TListViewItem in VCL had a Data property (of type Pointer) that you can set at runtime to an instance of an object. This was a little less naughty when moving to 64bit coding when Integer and Pointer all of a sudden became different sizes, (and if it wasn’t for some insight from the Delphi team to swap tag to NativeInt – lots of code would have broken).

The problem with a pointer property (or using a NativeInt to achieve the same goal) is that it leaves a lot of typecasting in your code, which never sat easy with me.

Avoiding tag / pointer properties….

A number of years ago, (probably when I was still using Delphi 5) I started to avoid using the tag property as a pointer holder by replacing the components I was creating with a new class that descended from the original component. e.g.

TMyButton = class(TButton)
strict private
  FFoo : TFoo;
public
  property Foo : TFoo read FFoo write FFoo;
end;

This approach reduced errors from typecasting, I had exactly what I was looking for and could write nicer code with less typecasting. I also often added the object to the constructor to make it easier and less lines of code.

Problems?

I also had times that I needed access to a number of objects, so would end up with multiple objects listed, when in reality I only needed to get to one or two properties of each objects.

I also had times that I had objects of different type (something a pointer is fine for), but it was always to get the ID value or something that was common.

FireMonkey Tag, TagObject, Data

FireMonkey components have not only a Tag property (that mimics the VCL, but it also provides 3 extra Tag’s

Tag Properties

  • Tag
  • TagObject
  • TagFloat
  • TagString

This can be easier to use, but there are sometime other values you want to pass and this is where the Data property comes into its own.

Data Property

Data is a TValue (from System.Rtti) and can be used to store pretty much anything. There are a load of helper classes for working with it, and some components even provide Data as an array with a string name.. (e.g. see the TListViewItem).

An example of using this is as follows

type
 TMyEnum = (Foo, Fee);
procedure TForm14.FormCreate(Sender: TObject);
var
 I: TListViewItem;
begin
 I := ListView1.Items.Add;
 I.Data['Foo'] := TValue.From('Hello');
 I.Data['MyEnum'] := TValue.From(TMyEnum.Fee);
end;
procedure TForm14.ListView1ItemClick(const Sender: TObject; const AItem: TListViewItem);
var
 Value : TMyEnum;
begin
 ShowMessage(AItem.Data['Foo'].ToString);
 Value := AItem.Data['MyEnum'].AsType<TMyEnum>;
 ShowMessage(TRttiEnumerationType.GetName<TMyEnum>(Value));
end;

You can see that even Enums can be passed using the Data property.

Using RTTI and the Data.TValue option provides a lot of flexibility in FMX for linking to objects or data.  Sometimes you may not need to create an instance of an object just to store the one or two lines of data that you required which can be useful and provides less memory to manage.

Summary

Thinking back to my POS screen, just having a string tag would have reduced a class that I needed to write test and manage the memory for.

Personally, for me, the data property is much more useful that an old style pointer – the TListViewItem with an array of TValues is also very useful.

2 thoughts on “Linking object/TValue to a control, VCL to FireMonkey”

  1. Stephen, XE8 doesn’t support creating android and ios service. If i want to collect some information about my activity (for example – gps coordinates) i must create app that will be working in background even if my app is closed. How to do this in XE8 (simplest way)?

Leave a Reply

Your email address will not be published.