LiveBindings in XE3: Updating Objects via an Adapter

Where I left off in my last post, we were able to bind our UI elements to an object, or indeed a collection of objects, by using the TAdapterBindSource combined with a TObjectBindSourceAdapter<T> or a TListBindSourceAdapter<T>.

Over a few posts I want to drill a bit deeper into what happens when you make changes to those objects, specifically in this post, when you make changes via the bound controls. I’ll explore the notification system that LiveBindings uses in later posts.

Let’s stick with the simple example of 3 edit boxes bound to my TPerson, via a TObjectBindSourceAdapter<TPerson>. We also want a TBindNavigator connected to the TAdapterBindSource.

If you run the app and start editing a value in the edit box, you’ll notice the Navigator changes state.

Our Adapter in Edit mode. Note the Post and Cancel buttons are enabled?

The Edit button becomes disabled, and the Post and Cancel buttons become enabled. A bit like a Dataset, right?

In fact, this is the key analogy to use when you are thinking of Adapters: think of them like Datasets.

In fact, this is the key analogy to use when you are thinking of Adapters: think of them like Datasets. If you have a look at the methods and properties exposed on the adapters, you’ll spot many that are similar or exactly the same as TDataset, eg:

  • A State property, of type TBindSourceAdapterState which has the values of seInactive, seBrowse, seEdit and seInsert
  • BOF and EOF properties, along with Next, Prior, First and Last methods.
  • Edit, Insert, Append, Post and Cancel methods.
  • Before and After events for Insert, Open, Post, Scroll, and on and on…

So your TListBindSourceAdapter<T> is almost like an object dataset for whatever type you specify in the T.

Once you come to grips with this, what I’m about to say next will hopefully be obvious.

When you edit a value in the Firstname edit box above, and then move over to edit the value in Lastname, because you have not yet called Post, those new values are not yet pushed back to your object. In fact they are buffered by the Adapter. Call Cancel (or press the Cancel button on the Navigator) and the values in the edit box will be restored to their original values.

You can see this in the example project, I have a set of edit boxes bound using LiveBindings, and as a result they will show the values in the Adapter. I also have a set of Edit boxes which get their values direct from the underlying TPerson object. In the period between going into edit mode on the Adapter and changing some values, and before calling Post, you can see they have entirely different values. Calling Post pushes the changes back to the underlying object.

This is pretty cool I think. A generic Object Dataset, providing buffered updates to my underlying objects.

One more thing before I wrap up this post. We can access the underlying object to see it’s values, and we can access the not-yet-posted changes via LiveBindings, but how do we get those same not-yet-posted changes via code? Like I said, think of the Adapter like a dataset. The InternalAdapter property of  TAdapterBindSource will give you a reference to the TBindSourceAdapter descendant that’s being used.

Once you have the Adapter, you can use FindField to get a reference to the individual fields like so:

var
  Adapter : TBindSourceAdapter;
begin
  Adapter := AdapterBindSource1.InternalAdapter;

  lblAdapterFirstname.Text := Adapter.FindField('Firstname').GetTValue.ToString;
  lblAdapterLastname.Text := Adapter.FindField('Lastname').GetTValue.ToString;
  lblAdapterAge.Text := Adapter.FindField('Age').GetTValue.ToString;

NB: careful, referencing TAdapaterBindSource.Adapter, instead of InternalAdapter, will give you whichever Adapter is configured at design-time, not necessarily the one being used at runtime. In our last example, that will give you the TDataGeneratorAdapter with all those Lorem Ipsum values.

There’s a sample project on github that illustrates the different values:

Our sample app, showing the values in Edit mode, prior to a Post. Values from LiveBindings (top), the Adapter fields (middle) and direct from the object (bottom)

7 Comments

  • How i show a data from a Inner Object Like  Person.Telefone.number in Visual Binding?

  • Better, How i show in the same GRID, like Person.name, Person.Age and Person.Telefone.Number

    • @arenapc I have a post planned on binding both from contained objects and also to composite controls.

  • We are expecting your post eager … about connecting the property to bind type TClass

  • Very interesting post ! Just a question: what happens  when I change a value directly in the object instance, will this change propagatet to the adpter ? In other words: is the link really bidirectional ?

    • @ssette Yes a good question, is it possible to set the link as true bidirectional?  I have not been able to.  I found the TBindings.Notify() does not work, and only using Refresh on the TAdapterBindSource or the Adapter itself will update fields that have been changed directly in the object instance.
       
      Also very interested to see more from Malcolm on MVVM.

  • Hi !!…
     
    Great Post and so functional… but i have a particular question.
     
    how can i update the TBindSourceAdapter or TAdapterBindSource??….
     
    i mean, if i have a 1 million records in a DataBase and i get 1000 of then per request, for the first request fine but for the follow request i can’t see the changes… how can i refresh or reload the Binding??.
     
    i hope you can help me…
     
    Greetings.

Leave a Reply to arenapc Cancel reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>