Video and supporting blog post exploring ProtoTypeBindSource
In the first post I covered how to link a DataSet to non data aware controls using LiveBindings in VCL. In this post we are going to move away from the DataSet and use Objects.
Working with Objects in Delphi is great, but building UI’s to interact with them has always been a bit time consuming. With LiveBindings, you can easily treat objects like they are data with a little bit of work. In this post and video I will look into how the basics work, before moving on from there.
Prototype Bind Source
TDataSets are great at enabling VCL application developers to see how the UI is going to look as its built, but how do you achieve that with objects that are only created at run time?
The answer is to use the powerful ProtoType Bind Source component!
- Firstly, the ProtoType Bind Source allows you to do something you have never been able to do with objects – See how data from them will look on the screen as your prototype your application.
- Secondly, the ProtoType Bind Source enables direct connection of objects to the UI without any code!
So how do we use this magic?
Adding fields to the PrototypeBindSource
First add a ProtoType BindSource to the application. It behaves a little like a dataset in setup and behaviour, so first we need to add in some fields. This is done double clicking on the ProtoTypeBindSource (or right click and FieldsEditor).
This displays the current fields in the prototype bind source.
There should be none listed at the moment, so go ahead and choose Add icon. (top left). Rather than being presented with a screen that asks you to define the size and type of the data you will be presented with a list of pre-installed Generators and the chance to specify a field name.
The Generators are sample data (many of which are paired together to give values that make sense when seen together) e.g BitmapNames (ftString) has values Bitmap28, Bitmap40 etc and the Bitmap (tfBitmap) has values that show images with 24 and 40 in the middle. Further down you will also find Generators that have no data and just provide a fields type.
My favourite (from a business point) are the ContactXXXXX generators as these provide great sample data for title, names and photos (with male and female names linked to gender relevant photos).
Once you have selected the Generator you want, enter a field name that will match the field you want to use on your object. – Don’t worry if you forget, you can always select the FieldDef later and change the Name in the Object Inspector.
Once you have sample data, you are now ready to build a UI.
Creating a Prototype UI with ProtoTypeBindSource
It is now time to add standard (non DB aware) controls onto the form and use the LiveBindings to link the prototype fields to the controls.
In the same way controls were linked to the UI using the DataSet in the first blog post on Visual Live Bindings with VCL and TDataSet, right click on the form and choose Bind Visually and then draw links between the controls and the ProtoTypeBindSource fields.
I suggest using a TListView and TEdit for a sample to see how Values can be changed easily.
You can also right click on the ProtoTypeBindSource and choose “Add Navigator” if you want to link navigation quickly using a BindSourceNavigator.
You can run the application to see and work with prototype data now. (If you are stuck… watch the short video)
Converting Prototype to Live
So, now prototype data is showing, how to convert it to live data?
The ProtoTypeBindSource has a single event on it
OnCreateAdapter(Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter);
This event has a variable ABindSourceAdapter that is used to pass back in the link between your object or object list and the PrototypeBindSource.
The most common thing to do here is either link one object, or a list of objects into the ProtoTypeBindSource to display on screen.
The list uses TListBindSourceAdapter – e.g. when linking to a list of TFoo objects
ABindSourceAdapter := TListBindSourceAdapter<TFoo>.Create(Self, FooList, True);
The single instance uses TObjectBindSourceAdapter with a pointer to the single object.
ABindSourceAdapter := TObjectBindSourceAdapter<TFoo>.Create(Self, Foo, True);
The last parameter defines if the Adapter or you will be managing the memory to the object passed in. If you are managing the list else where, then set that false.
Using PrototypeBindSource with global list.
Because the ProtoTypeBindSource is created with the form, the event to create the BindSourceAdapter fires as the form is created, before the Form.OnCreate event fires.
If you are using the Prototype BindSource with a global list then you are likely to have to override the form constructor and add in the pointer to the object / object list before inherited create is called. e.g.
constructor TForm1.Create(AOwner: TComponent); var Foo: TFoo; begin FooList := TObjectList<TFoo>.Create(true); Foo := TFoo.Create; Foo.Name := 'Stephen'; Foo.Value := 100; FooList.Add(Foo); Foo := TFoo.Create; Foo.Name := 'James'; Foo.Value := 200; FooList.Add(Foo); inherited; end;
If you do need to use the FormCreate, then you can always set the ProtoTypeBindsource active = false and then active = true, but you will need to ensure it is false at design time or it will already create the adapter internally.