Category Archives: Embarcadero Delphi

Delphi Shelf Life Reaches a New Low

I am going to try to keep this post short and to the point. I don’t want to rant (too much) or say anything I regret (too much), but something has to be said.

When it comes to iOS development, Delphi XE4, a major product released by Embarcadero five months ago, is now obsolete. If you want support for iOS 7 you must buy their new product, Delphi XE5.

Let’s take a step back and look at the facts when it comes to Delphi and Embarcadero chasing the mobile landscape:

  • Delphi XE2 – released September 2011. Claims support for iOS development but, by all reports, fails to deliver. iOS development makes use of the FreePascal compiler and cannot use traditional Delphi code.
  • Delphi XE3 – released September 2012. Support for iOS development completely removed. Anyone who built their iOS app on the foundation of XE2 was left out in the cold.
  • Delphi XE4 – released April 2013. Claims support for iOS development (again). Anyone who wants the iOS development support promised in XE2 must now buy XE4, released as a new product only seven months after XE3.

And now Delphi XE5 has been released only five months after Delphi XE4. It’s another new version and another paid upgrade.

Here’s the real rub though. iOS 7 was just released by Apple. It features a new UI and new navigation elements for apps. Anyone using Xcode (the traditional tool for iOS development which is free) could simply recompile their apps and resubmit them to support iOS 7.

What about Delphi XE4 customers? The ones who just put down their hard earned money for iOS support, again, five months ago? They are left out in the cold. Again. If a Delphi XE4 customer wants to support iOS 7 they must now purchase Delphi XE5. I confirmed this myself with a back-and-forth on Twitter with Jim McKeeth from Embarcadero:

Jim goes on to point out that, if you forgo using the bundled UI kit in your iOS app, you can still leverage the new iOS 7 elements using Delphi XE4:

However, this is basically suggesting the customer not use the same UI technology that is the very heart of Embarcadero’s marketing strategy for several releases now: FireMonkey.

To be clear, I am not upset by a six month release cycle. A lot of companies do that and it’s a smart move for some of them. However, Embarcadero is releasing Delphi like a subscription while selling it like a packaged product. While they offer “Software Assurance” this is a far cry from a subscription. This is an added fee on top of your purchase that allows you to get major upgrades that happen to be released within a year. It’s insurance. It’s the type of thing most of us pass up when checking out at Best Buy.

All-in-all this has just left a horrible taste in my mouth and the mouths of many other developers. My advice? If Delphi has turned into a subscription then charge a subscription. Stop packaging it as something that will be obsolete in 5 months without another purchase.

Advertisements

Improvements to Server Mode Grid in DevExpress VCL 12.2

Version 12.2 of the DevExpress VCL controls brings several improvements to the Server Mode feature of the ExpressQuantumGrid control. Both Advantage Database and PostgreSQL are now supported. There is also now support for in-place editing and banded table views when using Server Mode.

But one of the most welcome improvements, I think, is the new capability to specify custom SQL for the SELECT statement that the Server Mode data source components will use. When I last blogged about ExpressQuantumGrid Server Mode, the most vocal feedback was the need to specify custom SELECT statements. Until now this was only possible using Views within the underlying database. But starting with 12.2, DevExpress has introduced two new entries to the collection of Server Mode components to support using custom queries: TdxServerModeADOQueryDataSource and TdxServerModeDBXQueryDataSource. These are counterparts to the existing data source components that feature a SQL property for specifying the SELECT statement.

To see how easy this is to put into practice, download an open my sample from this blog post. Make sure you’ve also created a database and used the contained SQL scripts to create and populate the LotsaRows table.

Open Unit1 and select the Design tab. Delete the existing TdxServerModeADODataSource and replace it with a TdxServerModeADOQueryDataSource.

Setting up the TdxServerModeADOQueryDataSource component is very similar to setting up its non-query counterpart. For the Connection property select the existing ADOConnection1 component and for the SQLAdapter property, specify MSSQL Adapter. For the new SQL property, click the ellipsis button and enter the following SQL statement:

With the SQL statement specified, click the drop down arrow next to KeyFieldNames and select the ID column. Finally, set Active to True.

That’s it for setting up the TdxServerModeADOQueryDataSource. Now, select the Server Mode table view on the form and bind it to the TdxServerModeADOQueryDataSource using the DataController.DataSource property.

At this point you should see that the project is working again more or less as it did in my previous blog post. A million rows of data show, quickly, within the TcxGrid control, featuring fast grouping and sorting.

To actually see the new feature in practice, add a new TcxCheckBox to the main form, adjusting the grid control and giving it a proper caption.

And handle the Click event of the TcxCheckBox with the following code:

procedure TForm1.Column3CheckBoxClick(Sender: TObject);
var
  SQL: string;
begin
  //improve performance by disabling gridview updates during data operations
  cxGrid1DBTableView1.BeginUpdate;
  try
    dxServerModeADOQueryDataSource1.Active := False;

    //build SQL statement based on checkstate
    SQL := 'SELECT * FROM LotsaRows';
    if Column3CheckBox.Checked then
      SQL := SQL + ' WHERE Column3 = 1';

    dxServerModeADOQueryDataSource1.SQL.Text := SQL;
    dxServerModeADOQueryDataSource1.Active := True;
  finally
    cxGrid1DBTableView1.EndUpdate;
  end;
end;

And that’s it! By swapping out the existing TdxServerModeADODataSource for its query-enabled counterpart, we can now specify a custom SQL SELECT statement and still benefit from “blazing fast” population, sorting, and grouping of one million rows of data.

You can download the updated Delphi sample source code here.

Open Source Solution for Migrating from ExpressScheduler to XtraScheduler

Introduction

Express2XtraScheduler is a .NET solution consisting primarily of two assemblies and a WinForms utility that simplify importing database data from the format stored by the DevExpress VCL ExpressScheduler into a format supported by the WinForms XtraScheduler control.

Contents

  • Express2XtraScheduler.Core.dll provides the functionality needed to import data from one format to another given a pair of database settings
  • Express2XtraScheduler.UI.dll provides UI controls for mapping source and destination database settings
  • Express2XtraScheduler.exe uses these assemblies to provide a simple utility for transferring data
  • ExpressSchedulerInterop.dll is a Delphi DLL used to read resource information stored as Delphi variants

Express2XtraScheduler App

The solution also contains two simple applications that allow testing both VCL and WinForms scheduler data: ExpressSchedulerApp and XtraSchedulerApp.

Resources

Below are links to blog posts that discuss some of the techniques used by this solution:

Availability

The source code for the Express2XtraScheduler solution is available immediately on this public Git repo hosted at Bitbucket.

Getting Started with the DevExpress VCL Wizard Control

Version 12.2 of the DevExpress VCL controls contains the long awaited ExpressWizard control. DevExpress released a WinForms version, their XtraWizard control, over four years ago. They have now delivered a native version of this same control for the Delphi VCL.

Features of the ExpressWizard control mirror those touted by DevExpress for their XtraWizard control:

  • You can design dialogs that conform to either the Wizard 97 or Wizard Aero standard… creating standard based UIs has never been easier.
  • Cutting-edge interfaces are only a few clicks away and developers can be certain that their wizard control will look and feel the same as all other DevExpress controls within their applications.
  • By using DevExpress fade in/fade out effects, developers can easily enhance their wizards during page transition operations.

It’s worth noting that the ExpressWizard control is a new product in the VCL subscription. This means that, when installing 12.2, you should select “Modify and Update” rather than simply “Update”. This will allow you to select ExpressWizard for installation.

DX VCL Setup

To get started with the ExpressWizard control, create a new VCL Forms Application in Delphi. Next, use the File, New, Other menu item to display the New Items dialog. Select Delphi Files on the left. On the right you’ll see a new entry: DevExpress 12.2 Wizard Form.

New Items Template

Select this item and click OK.

Using this Wizard Form template nets you three things:

  1. A new form descended from TdxWizardControlForm. This is necessary to support the Aero glass features of the TdxWizardControl (similar to the TdxRibbonForm).
  2. A TdxWizardControl parented on the new form
  3. A single TdxWizardControlPage added to the wizard control

The TdxWizardControl is also found on the component palette and can be dropped on any form. However, if you want to use the Aero style wizard, you’ll need to change your form’s ancestor. Starting in this manner (versus the template) will also give you an empty wizard control with no pages.

To check out the basic features of the wizard control, I’d like a total of three pages: a Welcome page, an Agreement page, and a Finished page. For the Agreement page, I’d like the Next button disabled until the user checks a checkbox. I’d also like the wizard to use the Aero style rather than the Wizard 97 style.

Pages can be added to the wizard control in two ways, both available from the TdxWizardControl and TdxWizardControlPage context menus.

Wizard Context Menu

You can either click New Page directly, or click Page Collection Editor to display a dialog for managing the wizard pages.

Page Collection Editor

Using one of these two methods, add two new pages to the TdxWizardControl. As with the rest of the DevExpress VCL controls, the designtime editors and experience are top notch. You can actually click on the Next and Back buttons at designtime to switch through the wizard pages.

Use the Next and Back buttons to select each wizard page. Then, adjust the Header.Title property so that the pages read Welcome, Agreement, and Finish. You can also adjust the Header.Description property, but this line of text will not be visible when using the Aero style wizard.

Next, add a TcxCheckBox to the Agreement page in the wizard and adjust its Caption property to indicate accepting the agreement.

Added Checkbox

In order to show the wizard we’ll need some code on our main form. Open up Unit1 and click the Design tab. Add a TcxButton to the form. While we’re here, let’s take a very quick look at a new feature of the TcxButton in 12.2. Set the Kind to cxbkCommandLink. Assign values to both the Caption and CommandLinkHint properties. Bump the Font.Size property up to 12 and resize the control to fit its contents. Finally, assign a OnClick event handler with the following code:

uses Unit2;

{$R *.dfm}

procedure TForm1.cxButton1Click(Sender: TObject);
begin
  Form2 := TForm2.Create(Self);
  try
    Form2.ShowModal;
  finally
    Form2.Free;
  end;
end;

Click Run (or press F9) to check out the new button style.

TcxButton Runtime

Pretty nice huh?

Click the TcxButton to show the wizard dialog. You’ll see that, with no code, you can click Back and Next to navigate through the pages. In addition, the Back button automatically disables when you are on the first page. Also, the Next button caption automatically changes to Finish when you are on the last page of the wizard. However, clicking Finish and Cancel do not currently do anything. In addition, we need some code for our “agreement” and the wizard is still not the Aero style.

Close the app and return to Unit2. Select the TdxWizardControl and set the ViewStyle property to wcvsAero in the Object Inspector. Handle the OnCreate event of the TdxWizardForm itself with the following code to initialize the wizard:

procedure TForm2.FormCreate(Sender: TObject);
begin
  dxWizardControl1.ActivePageIndex := 0;
end;

Next, handle the OnClick event of the TcxCheckBox with the following code:

procedure TForm2.cxCheckBox1Click(Sender: TObject);
begin
  dxWizardControl1.Buttons.Next.Enabled := cxCheckBox1.Checked;
end;

Select the TdxWizardControl and handle its OnPageChanged event with the same logic:

procedure TForm2.dxWizardControl1PageChanged(Sender: TObject);
begin
  dxWizardControl1.Buttons.Next.Enabled := (dxWizardControl1.ActivePageIndex <> 1) or cxCheckBox1.Checked;
end;

Finally, handle the TdxWizardControl’s OnButtonClick event with the following code:

procedure TForm2.dxWizardControl1ButtonClick(Sender: TObject; AKind: TdxWizardControlButtonKind; var AHandled: Boolean);
begin
  if AKind = wcbkCancel then
    ModalResult := mrCancel
  else if AKind = wcbkFinish then
    ModalResult := mrOk;
end;

If you run the application again you’ll see the wizard is now functional. It starts on the Welcome page, and the Next button is disabled for the Agreement page unless the checkbox is checked. Finally, clicking Cancel or Finish dismisses the dialog.

Wizard Animated

Also, notice that each screen of the wizard fades in and out smoothly. Very nice!

You can download the Delphi source code for this example here.

Releasing the Source of VCL Controls based on DevExpress Look & Feel

The “cx-tras” package is a set of components I created nearly ten years ago and have been maintaining since. It is a set of visual components for Delphi that support DevExpress’s Look & Feel technology. This means that they automatically adjust their look based on the appearance and skin settings used in DevExpress VCL applications. The components were originally distributed by myself on request, then by DevExpress Support for a time, and now I’m giving them a home where anyone can access the source.

Various configurations for the Office Gizmo control

Demonstration of the Text Flow Panel control

Examples of the Close Button, Expand Button, and Size Grip

You can now access the source for the cx-tras package on Bitbucket here.

Emitting XtraScheduler Resource ID XML


I’ve recently been spending a bit of time directly accessing and manipulating the data that the DevExpress XtraScheduler emits when persisting its changes. You can read a bit about the structure of the data tables here and view the MSSQL schema here.

Most of the columns are relatively straight-forward, containing either strings or ordinal representations of enum values. However, the resource ID, reminder info, and recurrence info columns all contain specifically formatted XML strings. Luckily the DevExpress.XtraScheduler.XML namespace contains several helpful classes to assist in reading and writing these values.

In a previous blog post I discussed reading the resource ID’s stored by the VCL ExpressScheduler, returning them as a comma-delimited string. Given such a string called resources, in order to emit the proper XML you could do the following:

                string[] resourceArray = resources.Split(',');

                ResourceIdCollection idCollection = new ResourceIdCollection();
                foreach (string resourceID in resourceArray)
                {
                    idCollection.Add(int.Parse(resourceID));
                }

                AppointmentResourceIdCollectionContextElement element = new AppointmentResourceIdCollectionContextElement(idCollection);
                string xmlString = element.ValueToString();

With these few lines of code we have the necessary XML to access and store within the DB:

<ResourceIds>
  <ResourceId Type="System.Int32" Value="1"/>
  <ResourceId Type="System.Int32" Value="4"/> 
</ResourceIds>

In a future post I’ll discuss emitting the XML representations of reminder and recurrence info as well.

UPDATE: There’s a real-world example of this technique you can find here. It is an open source project for transferring data from ExpressScheduler to XtraScheduler.

Accessing ExpressScheduler Resource Information from .NET

In a previous blog post I discussed how to access the recurrence information that the VCL ExpressScheduler stores in its DB from a .NET application. Reading and writing the recurrence information is possible from .NET given a knowledge of the struct layout that the Delphi control uses.

However, if you want to read the resource information that ExpressScheduler stores in its DB from .NET, this requires using a Delphi DLL. This is because the Delphi scheduler control stores the resource ID’s for appointments in a single field but in multiple formats depending on the appointment. For instance, if the appointment has only one associated resource, its resource ID will be stored as a Delphi variant. However, the value will be stored as a Delphi variant array of variants if the appointment is associated with multiple resources.

Luckily, both Delphi and .NET make it straight-forward to interoperate between them and DevExpress has a simple utility method we can use to simplify things as well.

Start off with a new Delphi DLL project by clicking File>New>Other in Delphi XE2. On the New Items dialob, select Delphi Projects followed by Dynamic-link Library.


Start by adding both Variants and cxSchedulerStorage to the uses clause of the DPR. Then, add the following exported method to the DPR:

procedure ResourceIDBlobToString(const AResourceID: PByteArray; out AResult: PByteArray); export; stdcall;

var
  ResourceIDVar: Variant;
begin
  ResourceIDVar := cxFieldValueToVariant(AnsiString(AResourceID));
  if VarIsArray(ResourceIDVar) then
    AResult := PByteArray(VarArrayToArrayStr(ResourceIDVar))
  else
    //the cast to AnsiString below is necessary or a Unicode string will sneak in and gum up the works
    AResult := PByteArray(AnsiString(VarToStr(ResourceIDVar)));
end;

exports ResourceIDBlobToString;

This method uses the cxFieldValueToVariant utility method found in cxSchedulerStorage to translate the string representation of the field value to a Delphi variant. We then use VarIsArray to test if the variant is an array. If it is not, we simply return the variant as a string. If the variant is a variant array, we will use the following method to parse it:

//input is a variant array of strings
//output is a comma delimited string composed of the members of the input array
function VarArrayToArrayStr(const ResourceIDArray: Variant): AnsiString;
var
  I: Integer;
begin
  Result := '';
  for I := VarArrayLowBound(ResourceIDArray, 1) to VarArrayHighBound(ResourceIDArray, 1) do
  begin
    if Result <> '' then
      Result := Result + ',';
    Result := Result + VarToStr(ResourceIDArray[I]);
  end;
end;

This simple function iterates through the variant array using VarArrayLowBound and VarArrayHighBound, building up a comma-delimited list of the resource ID’s.

And that’s it for the Delphi DLL.

Next we’ll create a new C# WinForms solution to test out our DLL. Click File>New>Project and select a Windows Forms Application.


I’ll skip the data access code as it’s straight-forward. The interesting bit here is the DllImport attribute we’ll use to call our Delphi DLL:

[DllImport("ExpressSchedulerInterop.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
static extern void ResourceIDBlobToString([MarshalAs(UnmanagedType.AnsiBStr)] string resourceID, [Out, MarshalAs(UnmanagedType.AnsiBStr)] out string result);

With this method defined properly, the following code can be used to read the resource data from the DB in C#:

string result = null;
ResourceIDBlobToString((string)reader["ResourceID"], out result);

You can download a Delphi scheduler app here, the Delphi scheduler interop project here, and the C# example data reader here.

UPDATE: I updated the code in this Blog post, along with the interop Delphi project source, to address a bug when using Unicode versions of Delphi. A cast to AnsiString is necessary or only the first character in the resource ID will be returned.

UPDATE #2: There’s a real-world example of this technique you can find here. It is an open source project for transferring data from ExpressScheduler to XtraScheduler.