Tuesday, May 13, 2014

Simplifying LiveBindings Configuration in Mobile Apps Using Frames

Unless you have been sleeping under a rock, you already know that Delphi can create native executables for both iOS and Android mobile devices. These applications must be created using FireMonkey, since FireMonkey is Delphi's cross-platform component library. When using FireMonkey, most developers make use of LiveBindings and the LiveBindings Designer to enable data awareness in the visual controls.

Unfortunately, the evolving best practices for mobile application design in Delphi has relied on applications based on a single form, where a TabControl containing two or more TabItems defines the various screens (pages) of the application.

This design avoids some of the issues associated with having multiple forms in a mobile application. For example, Android applications do not support the concept of non-modal forms, and although iOS does, the active form always occupies the entire screen.

Another issue related to having more than one form in a modal application is related to mobile device orientation. Specifically, many applications will re-orient themselves when a user rotates their device 90 degrees, switching from a portrait view to a landscape view and back. The problem here is that the OnResize event is received only by the form with focus. No other forms in memory receive this event, and therefore may not be aware that orientation has changed.

If a mobile application needs two or more pages (or views or forms or whatever you want to call them), this can be achieved by including a single form on which a TabControl appears. You then create one TabItem for each page of the application, and provide user interface elements such as menus, tabs, or buttons to navigate between the available TabItems. In fact, this is the model used by all of Delphi's multi-page wizards in the Object Repository, which you can select from when you select File | New | FireMonkey Mobile Application from Delphi's main menu.

While the TabControl/TabItem configuration works, it introduces an unwanted side effect. Specifically, if you use the LiveBindings Designer to visually bind your controls to BindSourceDB components, every control appears on the default layer, and the designer quickly becomes cluttered, making it difficult to create and manage your LiveBindings. And even though the LiveBindings Designer permits you to define layers on which to display select controls, the clutter remains a challenging issue. And, the clutter increases in direct proportion with the overall number of controls on your one form. This can be seen in the following view of the LiveBindings Designer for a somewhat simple two TabItem TabControl.

 
Unfortunately, a two-page mobile application is uncommon. Most mobile applications will have many more pages (TabItems), and the problem of clutter in the LiveBindings Designer can get completely out of hand.

There is another solution, however, and it can be found in FireMonkey frames, which were added to FireMonkey in Delphi XE3 (the VCL introduced frames in Delphi 5, and I have found them to be invaluable in my Windows applications).

Here's the deal. A frame is a design surface, and each design surface in Delphi has its own LiveBindings Designer. As a result, only those controls that appear on the frame automatically appear when you view the frame's LiveBindings Designer.

Here is what you can do. In the simplest case, you create one frame for each TabItem that you will include in your single form application. You then place each frame into its corresponding TabItem, and then align the frame to alClient. If you want to get really clever, you might even place two or more frames into a single TabItem, but that is a design issue.

For each frame, you include in its uses clause only those data modules whose TDataSets you want to bind using LiveBindings. The result is that each LiveBindings Designer includes only a subset of controls that appear in the single form. This can be seen in the following view, which shows a frame that replaces the controls that appear on the first TabItem of the form whose LiveBinding Designer was shown earlier in this post.

 
The problem is not entirely solved. Specifically, the one form of your application on which the TabControl appears will display all of the objects from all of the frames placed on the individual TabItems within the LiveBindings Designer when the form itself is selected in the designer, so the clutter still exists. But you will not really care. As long as you can configure LiveBindings at the Frame level, you will use the LiveBindings Designer only with individual frames, in which case only the components on the selected frame will be visible. Furthermore, the benefits of this frame-by-frame configuration will increase in direct proportion to the number of TabItems on your form.

This is just one of the tips, along with many other fun and useful Delphi techniques, that I will be covering along with Bob Swart (Dr.Bob) at this years Delphi Developer Days 2014 tour. We have completed our first two cities in the United States, and the response was excellent. We now continue on to Frankfurt, Germany on May 26th and 27, Amsterdam, The Netherlands on June 12th and 13th, and London, Great Britain on June 18th and 19th. For more information and to register, please visit http://wwwDelphiDeveloperDays.com.

Copyright (2014) Cary Jensen. All Rights Reserved

2 comments:

  1. Good tip. One thing I would say about Frames (at least in XE5 - not sure about XE6) is that the IDE doesn't do as good a job at supporting styles. So if you're in Android mode, your buttons on a form will look like Android buttons, but on a frame they just look like buttons. Also the combo list of styles available for controls isn't fully populated, though you can style type in the name of the style you want and it will display correctly at run time, eg. ListViewItemBottomDetail.

    ReplyDelete