Looking forward to seeing the gang from the UK Developer Group at a session today in Maidenhead UK.
Come along and see RAD Studio XE2 in action with myself and Glenn Wylie if you can make it.
Agenda details are here….
UK Developer Group Meeting
Glenn - don’t forget the FireMonkey T-shirts!
Share This | Email this page to a friend
Delphi XE2 introduces unit scope names, which means that a unit name gets a prefix in the RTL, VCL and FMX libraries.
Since it's not always immediately obvious which of the 31 Delphi XE2 unit scope names should be used to prefix a given unit, I've written a little web application that may help in turning an original unit name into a scoped unit name (like SysUtils turning into System.SysUtils).
To be honest, FireMonkey did not interest me much because of the fact that it is not compatible with any VCL application - says the documentation - actually that's not the truth!To keep the long story short: You can have both in one! (Disclaimer: I did only a few tests and it worked all fine - actually I have no clue if somewhere it's incompatible but I leave that as an exercise to you).Just create a new FireMonkey form (2D or 3D, doesn't matter) save it and then add it to your VCL application (just accept the warning). You can create your FMX form instance somewhere and just show it - no problem. But what if you want to create some nice control with animations or something and embed it into your existing VCL form? Well, put a TPanel on your VCL form and include the brandnew unit DSharp.Windows.FMXAdapter.pas after the Vcl.ExtCtrls. Then just create your FMX form somewhere and assign it to the new Form property of your Panel - and boom, there you go.As I said, I just came up with this and it's mostly untested - but that's the case for FireMonkey anyway, isn't it? So I thought this may be very interesting for a few people - especially those that used VGScene before. So have fun creating your shiny and new FMX forms and use them in your existing VCL apps. ;)
This is not an article about LiveBinding. I was once hoping it was going to be, but instead it has become an alternative to LiveBinding. If anything, it is about compile-time binding and quality assuring the data input from of your users. Forms, forms, forms...How many forms have you created? Chance is - quite a few - and what do they have in common? If people type rubbish, your data becomes rubbish. So - what do you do? You validate the input to prevent rubbish getting into the system. You do... don't you? Sure you do!When do you validate it? When someone clicks Submit or OK? Right - then you have to go through the input, field by field, and first ensure that what the user typed in actually is understandable in the current context - such as no funny characters in an integer - and sometimes you have to check the values against each other for logical states. If someone said they took three melons, their combined weight should at least be bigger than zero, and blue shirts don't go well with pink pants, and what else not.If the user typed in rubbish - you have to inform him or her so that it can be corrected.Been there, done thatThere is a certain amount of logic in this scene that we keep recreating scaffolding for. Stuffing things into listboxes, formatting and filling in the values, validation of numbers and dates, converting enumerated types into strings (and back again). If you want the dialog to be slick - you might even want to validate as you go, which means eventhandlers for focus changes, keys pressed, UI items clicked, dropped down and selected, also adding to all the scaffolding code.Some time ago, I had to create yet another dialog. Lines and lines of housekeeping code that surround the real validation logic. And naturally I don't have to be clearvoyant to foresee numerous more such dialogs, as it is a major part of writing applications that deal with configuration, input and control.So - I thought to myself - can I spend a little time now, and save a lot of time later? Dangerous, innit, thinking like that... suddenly you could find yourself writing a framework, and we all know what happens to frameworks, right? They turn to endless amounts of code written with good intentions of handling the unexpected, covering functionality you won't ever need, and at some point collapse on themselves to become a black hole of sketchily documented (since noone updated the docs as new features got added) , and hastily changed (since you always are in a hurry for that extra functionality) code. And when someone else misread your framework intentions and applied it like a hammer to a screw - it just doesn't end well.Narrowing down the scopeHence - Sticking with the KISS principle, I have decided to try to make it independent of other libraries, and limit what I implement to basic functionality while attempting to allow for future expansion.I am going to create a TInput<T> that wraps a GUI control. To put it simply - a TInput that points to a specific TEdit, and takes care of stuffing values from the variable and into the GUI control, and vice versa. The job of that TInput<T> is the present the value correctly, and to ensure that what ever is written into that TEdit, can be converted into an integer.I will also create a TInputList that is a collection of TInput<T>s, that will have the job of going through the list to fill the controls, to validate the contents, and finally - if all input is syntactically correct - semantically validate the input for logical correctness.Some of the code that I will present here, is probably centric to the type of data that I work on. For me, an input form will typically wrap an object with a set of properties that reflect a row or set of related rows in a database. Why am I not using data aware controls? Mostly because the applications we create actually can't write to the database themselves, except through calling stored procedures that perform more magic before, during, or after the data has been written. For that reason, the TInputList will be a TInputList<T>, and the TInputList<T> will have a property Current:T that I can populate, and each TInput<T> will know that it is member of a TInputList<T>, so that it can kick of the necessary actions for stuff to get validated.[kom-pli-kei-tid]By now you have probably thought to yourself: TEdit? What about the other controls?Because there are a number of input types, and a number of controls, and these make a number of combinations. TEdit/Double, TEdit/Integer, TEdit/String, and TEdit/Enum is already a list, and I haven't even mentioned TComboBox yet,- so it is obvious that TInputList<T> has to be polymorphic.This brings us to the first part of complicated - creating a set of generic and polymorphic classes. Generics in Delphi XE still don't to well with forward declarations, and to create polymorphic parent/children lists, it really helps to be able to forward declare.After some consideration, I have chosen to use an abstract class without generics as my inner base class. TAbstractInput will know nothing about the data type we want to work with, nor will it know anything about the control type. All TAbstractInput will do, is define the virtual abstract methods that will be our type agnostic operators or verbs and queries, if you like. Hence, our TInputList will use TAbstractInput as its element type./// <summary> TAbstractInput defines the bare minimum base class for our list of inputs <summary>
TAbstractInput = class abstract
function GetEdited: Boolean; virtual; abstract;
procedure SetEdited(const Value: Boolean); virtual; abstract;
function GetEnabled: Boolean; virtual; abstract;
procedure SetEnabled(const Value: Boolean); virtual; abstract;
function ControlValueIsValid:Boolean; virtual; abstract;
function VariableValueIsValid:Boolean; virtual; abstract;
procedure FillControl; virtual; abstract;
procedure FillVariable; virtual; abstract;
procedure SetDisabledState; virtual; abstract;
procedure SetErrorState; virtual; abstract;
procedure SetNormalState; virtual; abstract;
procedure SaveNormalState; virtual; abstract;
procedure Setup; virtual; abstract;
procedure Clear; virtual; abstract;
procedure Update; virtual; abstract;
function Validate: Boolean; virtual; abstract;
property Edited: Boolean read GetEdited write SetEdited;
property Enabled: Boolean read GetEnabled write SetEnabled;
From the outside of the list, we need TInput<T> that expose the correct type that we want to access, so that will be our outer base class type - which knows how to set and get the value, and hence the class that we use to reference an input field./// <summary> TInput<T> defines the input wrapper as we want it to be
/// visible from the outside of our list of controls</summary>
TInput<T> = class abstract(TAbstractInput)
procedure SetOnCanGetValue(const Value: TGetValue<Boolean>);
function GetValue:T; virtual; abstract;
procedure SetValue(const Value:T); virtual; abstract;
function CanGetValue:Boolean; virtual; abstract;
property Value:T read GetValue write SetValue;
property OnCanGetValue: TGetValue<Boolean> read FOnCanGetValue write SetOnCanGetValue;
Please note that this is a simplified view of TInput<T> class. Inside TInputList, I will subclass TInput<T> again, and add knowledge of the controls. In fact, I will create several subclasses that handle type conversions for each data type and control type, but instead of having the user instantiate all these different class types - I will add factory methods to the TInputList instead.Here are some excerpts from the declaration of TInputList and the basic control wrapper./// <summary> TInputList is a wrapper for all our input controls. </summary>
TInputList<IT:class, constructor> = class(TList<TAbstractInput>)
/// <summary> This is our core input control wrapper on which we base wrappers for specific controls </summary>
TInputControl<TCtrl:class; SVT, CVT> = class(TInput<SVT>)
Properties and BindingThis is the second part of complicated. Will I be using the XE2 LiveBinding? No. IMO, LiveBinding uses the least desirable method to bind a property for setting and getting. I lamented this in my previous article, Finding yourself in a property bind. In my opinion, LiveBinding is a good idea that is implemented in the wrong way, and in it's current form will be vulnerable to property and variable name changes during refactoring. In addition, it appears that LiveBinding is not quite mature yet. Then there is the fact that XE and older, doesn't have LiveBinding.After some experimentation, I came to the conclusion that even if it appears to be more elegant to use visitors or observers and RTTI binding, I will get more flexibility, readability, and maintainability by using anonymous methods. Anonymous methods allow me to do manipulation of the value before it is set/get, and allow the setter/getter events to have side effects. It also ensures that all references are validated compile-time. It will not guarantee protection from referencing the wrong properties and variables, but they will at least be of the right type, and actually exist.Since my primary development platform is Windows, I am a VCL developer - and when I started this little project, I had only VCL in mind. However, as the code matured, I found that I might want to be able to use this for FireMonkey as well. That still remains to be seen as FireMonkey still smell of Baboon.Still, the core logic is platform agnostic, and the VCL bits are separated into a unit of their own.Here is an excerpt from the VCL implementation with complete declarations.TInputListVCL<IT:class, constructor> = class(TInputList<IT>)
TInputControlVCL<TCtrl:TWinControl; SVT, CVT> = class(TInputList<IT>.TInputControl<TCtrl, SVT, CVT>)
procedure ControlEnable(const aState:Boolean); override;
function ControlEnabled:Boolean; override;
procedure ControlSetFocus(const aFocused:Boolean); override;
/// <summary> Basic wrapper for a TEdit </summary>
TEditTemplate<SVT> = class abstract(TInputControlVCL<TEdit, SVT, String>)
procedure SetControlValue(const Control:TEdit; const v:String); override;
function GetControlValue(const Control:TEdit): String; override;
function ControlValueAsString:String; override;
procedure SetErrorState; override;
procedure SetNormalState; override;
procedure SaveNormalState; override;
procedure SetDisabledState; override;
procedure Clear; override;
procedure Setup; override;
/// <summary> TEdit wrapper for editing a string </summary>
TEditString = class(TEditTemplate<String>)
function ConvertControlToVariable(const cv: String; var v:String; var ErrMsg:String):Boolean; override;
function ConvertVariableToControl(const v:String; var cv:String):Boolean; override;
/// <summary> TEdit wrapper for editing a float </summary>
TEditDouble = class(TEditTemplate<Double>)
procedure SetDecimals(const Value: Integer); override;
function GetDecimals:Integer; override;
function ConvertControlToVariable(const cv: String; var v:Double; var ErrMsg:String):Boolean; override;
function ConvertVariableToControl(const v:Double; var cv:String):Boolean; override;
Putting it to useThis will be covered in part 2. Until then, don't forget to try out RAD Studio XE2 and join the RAD Studio World Tour presentations!
While prolly almost everyone was creating fancy FireMonkey or VCL applications for Windows (32-bit and 64-bit), OSX and/or iOS with Delphi XE2 today I took a look at one of my favorite units in the RTL - System.Rtti.pas.When you look at the RTL Changes for XE2 you will see a new addition to the RTTI - TVirtualInterface. Along with this comes another improvement: RTTI can finally tell the implemented interfaces of a class (and its ancestors). But back to the TVirtualInterface!Documentation says: "Provides functionality for remote procedure call marshaling. TVirtualInterface creates an implementation of an interface at run time." Wow, this sounds interesting. Further reading states that it's main purpose is SOAP messaging. A client can consume a service with several methods just by calling them through an interface which then "just calls" the remote methods of the service. I think this is awesome because it leads to clear defined interfaces (literally) when working with remote services or other things that just hide behind the interface and which are not necessary to be known. Other things I say...Some while ago when I came across the Emballo Framework I was impressed by the DLLWrapper which basically imports exported functions of a DLL and provides them through an interface. Of course there have to be some rules like the calling conventions and the parameters have to match. But you can do define an interface like this:type
IMyLibrary = interface
function SayHello: string
end;And then simply import a DLL which exports this function and just call it. It was a bit rough and actually only supported a few types and not all calling conventions. So I am very happy to have a tool out of the box that makes it possible to write something like this:if Supports('MyLibrary.dll', IMyLibrary, LMyLibraryIntf) then
Those of you that worked with .Net in RAD Studio 2007 may know this - it was called Virtual Library Interfaces. I have not tried yet, but I am sure if you have the correct signature in your interfaces methods you can call almost every DLL. Actually the Supports functions does not exist in Delphi but you can find it in the brand new unit DSharp.Core.Plugins.I uploaded a simple sample how to use this (including the new unit which can also be downloaded from the svn repository).I also added the DSharp packages for XE2 today (only 32-bit for now, 64-bit compatibility will follow soon). I know there is some issue with the asm code in the DSharp.Core.Events (that has to go for 64-bit anyway) which break bindings for now - but I am working on it. Also more about LiveBindings vs DSharp soon.
If you follow Delphi at all, then you will have noticed lots of recent activity around the upcoming release of Delphi (Rad Studio) XE2. And with big ticket items like native 64 bit, Mac and iOS support, FireMonkey, VCL themes, data binding (VCL and FireMonkey), etc, there is a lot to be excited about. I find myself looking for opportunities to use some of these new features.
However, and with
Since the start of the RAD Studio XE2 World Tour the word is out. Delphi XE2 will have 64-bit compiler, support for OSX and iOS applications with their new FireMonkey GUI framework and LiveBindings. If you haven't read the detailed RAD STUDIO XE2: Launch Event Report yet - now is the time to do it.When I heared about some built-in data binding architecture for the first time I was very excited. It was just a headword on the roadmap for Project "Wheelhouse" but now we know it will be coming with XE2!Unfortunately there have been much more informations and speculations about the 64-bit compiler, the support for other operating systems and the FireMonkey framework than for those LiveBindings.On the official Embarcadero forums there has been some discussion about what to expect. WPF and Cocoa have been mentioned. It has also been mentioned in Auckland that there will be some expression engine to do more than just simply add the TCustomer.LastName property to some TEdit.Text but use some kind of scripting. How will this work? Will there be some designtime support for it to make sure you don't have typos in it (one of the major drawbacks in my current implementation)? Also will the whole binding architecture be supported by new language features to make it save at compile time (like property references or built-in change notifications)?Lots of questions but only few informations (yet). But we can guess, speculate and wish. So please feel free and leave a comment about what you expect from LiveBindings in Delphi XE2.