TestComplete 7 – A Killer Feature

•August 19, 2009 • Leave a Comment

So far I’m digging the upgrade from TestComplete 6 to 7. I’ve been a TestComplete user for several years and love the product. I’ve always been fond of AutomatedQA’s tools – we also use Automated Build Studio (in addition to FinalBuilder). Their applications are both powerful and attractive (what can I say, I’m a sucker for DevExpress user interfaces).

Recently, one of TestComplete 7’s new features has really stood out for me at work. No, it’s not keyword testing. While keyword testing has gotten most of the press and is, arguably, very cool for getting up and going with UI testing, the feature I’m loving is this: it’s no longer necessary to compile Delphi and C++Builder applications with special units in order to fully test them.

With previous versions of TestComplete, it was necessary to compile Delphi and C++Builder applications with certain units that allowed TestComplete to “see” the VCL controls rather than just the window handles and Windows controls. Running applications that were built against these units, but without TestComplete installed, resulted in a nasty error dialog. So, it was generally necessary to have scripts that built testing versions of all of our applications, placed those in a working directory, and then run our test scripts against those builds.

This is no longer necessary. Not only does this reduce the complexity of our testing process (which is A Good Thing) but, more importantly, this allows us to now test actual releases of our applications. We’ve begun rewriting our test scripts to install the same setups and updates our build process has created for our customers, and then test against those release versions. This provides us with much more accurate testing and will benefit our customers greatly, allowing us to catch bugs that may have made it into our releases but would not have been caught by testing special builds of the software.

Kudos to the team at AutomatedQA for another fine release of a great tool.

tide.Northwind.Customers – Part 2

•August 15, 2009 • Leave a Comment

In my previous post on the Customers plugin for the tide Northwind demo, we created an IMasterWindow plugin that displayed the Northwind customers, and allowed for inline editing within DevExpress’ .NET GridControl. This enabled us to create, edit, and delete customers from the Northwind database. However, as I expressed before, I’m not a huge fan of editing within a grid, unless I know the target audience is very savvy. With that in mind, we’ll now create an IDetailWindow plugin that allows us to inspect the details of a row, and make changes within that window, rather than in the grid control itself.

First, let’s look at the key methods within tide that we’ll either be calling or implementing within our plugins:

  • void IHostApplication.DisplayMasterDetails(IMasterWindow sender)
    Called from IMasterWindow plugins to display relevant detail windows.
  • void IHostApplication.DisplayDetailWindow(IMaserWindow parent, IDetailWindow plugin)
    Called from IDetailWindow plugins to display themselves, parented in an IMasterWindow plugin.
  • void IDetailWindow.DisplayDetails(IMasterWindow)
    Implemented by IDetailWindow plugins, to handle displaying details for relevant IMasterWindow plugins.

Let’s get started. We’ll start by adding a new Hydra Visual Plugin to our existing Northwind.Customers Hydra Plugin Module project. Then, we’ll copy the customers binding source from our previously created BrowsePlugin form to our new plugin form, add several DevExpress TextEdits to a LayoutControl instance, and bind them to the customers binding source.

As before, we’ll add a couple of tide namespaces to our using clause:

using tide.PluginInterfaces;
using tide.Utilities.Plugins;

The tide.PluginInterfaces namespace gives us access to the various plugin interfaces that can be implemented. The tide.Utilities.Plugins namespace provides some base classes we can descend from that give us some nice built in functionality. We’ll call this plugin DetailsPlugin and adjust its declaration as shown below:

public partial class DetailsPlugin : DetailWindow

The DetailWindow class, declared in tide.Utilities.Plugins, implements IDetailWindow with default methods. It also descends from BaseWindow, which has some niceties such as automatically persisting DevExpress GridControl changes and LayoutControl customizations.

IDetailWindow works hand-in-hand with IMasterWindow, providing a detail view for the data presented in a class that implements IMasterWindow:

public interface IDetailWindow
{
    void DisplayDetails(IMasterWindow sender);
    bool BeforeSaveDetails(IMasterWindow sender);
    bool AfterSaveDetails(IMasterWindow sender);
    string Caption();
    int Order();
    Image Glyph();
}

Some of IDetailWindow’s methods relate to how the view is presented in the application, such as Caption(), Order(), and Glyph(). Others, such as DisplayDetails(), BeforeSaveDetails(), and AfterSaveDetails(), allow our class to respond to certain events that happen to the IMasterWindow, such as displaying that IMasterWindow’s DetailsObject(), and taking certain actions before or after the IMasterWindow’s DetailsObject() is saved.

We’ll override a few of the DetailWindow methods in our DetailsPlugin, giving us what we need to view the details of a Northwind customer:

public override void DisplayDetails(IMasterWindow sender)
{
    if (sender is BrowsePlugin)
    {
        RemoveControlErrors();

        customersBindingSource.SuspendBinding();
        customersBindingSource.DataSource = sender.DetailsObject();
        customersBindingSource.ResumeBinding();

        (Host as IHostApplication).DisplayDetailWindow(sender, this);
    }
}

public override bool BeforeSaveDetails(IMasterWindow sender)
{
    return dxValidationProvider1.Validate();
}

public override string Caption()
{
    return "Customer Details";
}

public override Image Glyph()
{
    return imageCollection1.Images[0];
}

Our DisplayDetails() implementation checks to see if the calling IMasterWindow is our BrowsePlugin. If so, it simply binds the IMasterWindow’s DetailsObject() to the binding source on our form, and then calls the host’s DisplayDetailWindow() method, which shows the detail window parented in the specified master window.

We also override BeforeSaveDetails() so that we can use a dxValidationProvider to ensure the necessary values are filled in for our customer. The call to RemoveControlErrors() in DisplayDetails() is simply a helper method that removes any existing validation errors when a new object’s details are shown.

Now, we’ll alter the code we wrote before in our BrowsePlugin so that, instead of editing within the grid, our IDetailWindow implementation is displayed instead. We’ll be using a second dataset, editingNorthwindDataSet, as a temporary holding place for the row we are editing. This allows us to make changes in our IDetailWindow plugin without directly affecting the list in the IMasterWindow plugin until the changes are saved.

First, we’ll change our NewItem() method from:

public override void NewItem(object refId)
{
    customersBindingSource.AddNew();
}

to:

public override void NewItem(object refId)
{
    editingCustomersRow = editingNorthwindDataSet.Customers.NewCustomersRow();
    InitializeCustomerRow(editingCustomersRow);

    editingNorthwindDataSet.Customers.Rows.Clear();
    editingNorthwindDataSet.Customers.Rows.Add(editingCustomersRow);

    (Host as IHostApplication).DisplayMasterDetails(this);
}

Here, we create a new row, initialize it with default values, and add it to our editing dataset. Then, we call the host’s DisplayMasterDetails() method, which will iterate through plugins that implement IDetailWindow, calling DisplayDetails() on them, passing in the calling IMasterWindow.

In order for this to work (as seen in our IDetailWindow plugin’s DisplayDetails() implementation above), we need our BrowsePlugin to override DetailsObject(), returning the object that our IDetailWindw plugin is interested in. In this case, it’s our editing row:

public override object DetailsObject()
{
    return editingCustomersRow;
}

Then, we’ll change our implementations of SaveItemEnabled() and SaveItem() from:

public override bool SaveItemEnabled()
{
    return northwindDataSet.HasChanges();
}

public override bool SaveItem()
{
    customersTableAdapter.Update(northwindDataSet.Customers);
    return true;
}

to:

public override bool SaveItemEnabled()
{
    return editingNorthwindDataSet.HasChanges();
}

public override bool SaveItem()
{
    customersTableAdapter.Update(editingNorthwindDataSet);
    northwindDataSet.Customers.LoadDataRow(editingCustomersRow.ItemArray, System.Data.LoadOption.OverwriteChanges);
    return true;
}

Here, we’re simply checking our editing dataset for changes rather than our browsing dataset. With SaveItem(), we save our editing dataset rather than our browse dataset, and we load the added/updated row back into our browsing dataset. Easy enough!

Now, we’ll change our DeleteItem() implementation slightly. Before, since we were editing within the grid, we simple removed the current row in our DeleteItem() implementation:

public override void DeleteItem()
{
    customersBindingSource.RemoveCurrent();
}

These changes would be saved in our previous SaveItem() implementation. However, we’ve now changed the paradigm. DeleteItem() needs to apply the changes, so we’ll make some slight modifications, adding a message dialog to confirm our deletion and then applying the changes:

public override void DeleteItem()
{
    if (MessageBox.Show("Delete the selected customer?", "Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
    {
        customersBindingSource.RemoveCurrent();
        customersTableAdapter.Update(northwindDataSet);
    }
}

The final piece to making this all work is disabling editing in our GridControl by toggling OptionsBehavior.Editable, and then handling the GridControl’s DoubleClick event with the following code:

private void customersView_DoubleClick(object sender, EventArgs e)
{
    NorthwindDataSet.CustomersRow customersRow = (NorthwindDataSet.CustomersRow)northwindDataSet.Customers.Rows[customersBindingSource.Position];

    editingNorthwindDataSet.Customers.Rows.Clear();
    editingNorthwindDataSet.Customers.ImportRow(customersRow);
    editingCustomersRow = (NorthwindDataSet.CustomersRow)editingNorthwindDataSet.Customers.Rows[0];

    (Host as IHostApplication).DisplayMasterDetails(this);
}

Similar to our NewItem() implementation, we’re mostly just juggling dataset rows. We take the current customer row in our browsing dataset and import it into our editing dataset. We save a reference to our editing row (as it is used by our DetailsObject() implementation), and then call the host’s DisplayMasterDetails() method (as in our NewItem() implementation). As stated above, this will display our IDetailWindow plugin, parented in our IMasterWindow plugin.

And that’s it! You can now create and edit customers within a dedicated detail window:

Widgets and Gadgets Northwind Client (4)

You can have as many IDetailWindow implementations as you like. For each one that calls IHostApplication’s DisplayMasterDetails method for a given IMasterWindow, tabs will be created for displaying each IDetailWindow plugin (that’s where the Order() method comes into play). You can also have completely separate Hydra Plugin Modules with IDetailWindow plugins that parent in IMasterWindow plugins from other modules. It’s all fairly loosely coupled, while allowing for a nice degree of integration between plugins.

In the next post, we’ll get into creating a plugin for Northwind Orders, and show how to do things such as showing customer details from an order’s details or creating a new order from a selected customer’s details.

DevExpress Gems – The VCL Filter Control

•August 3, 2009 • 3 Comments

Recently, at my day job, I was tasked with creating a visual query builder for the reporting in one of our software products. The existing query builder was pretty simplistic, and did not allow for grouping conditions. After talking to a few colleagues and looking into some recommended solutions, a consultant and coworker (and close friend) of mine suggested something that is now obvious, but at the time caught me off guard: why not try utilizing the same filter control shown when you customize the filter of the DevExpress VCL Quantum Grid?

Using the filter control from the Quantum Grid component would immediately carry several benefits:

  • We wouldn’t have to purchase an additional control
  • Our query builder for reports would be the same control customers already use to customize our grids
  • Our query builder for reports would visually match the rest of our application

I was optimistic about being able to reuse the filter control, but honestly thought I’d be digging into the source for the existing Quantum Grid filter customization dialog, hoping for some source I could use. Once I sat back down to my development environment, I was delighted (to say the least) to find both TcxFilterControl and TcxDBFilterControl in my tool palette. This was not the first time (nor, I suspect, the last) that I was completely surprised to find some controls in my DevExpress arsenal of which I was previously unaware.

Did these controls allow us to provide a flexible query builder capable of creating complex SQL? You betcha.

Out of the box, TcxFilterControl is meant to be wired up to something like a TcxGrid table view, while the TcxDBFilterControl is meant to be wired up to a TDataSet descendant. While I normally shy away from database-aware controls in the VCL, the TcxDBFilterControl seemed to be more suited for our needs.

To get started using a TcxDBFilterControl, you can simply drop the control on a form and hook it up to a TDataSet descendant. Immediately, the control is capable of creating complex filters, with the field selections in the filter control populated with the field definitions from the TDataSet descendant.

If you are working with a standards compliant SQL engine, using the TcxDBFilterControl to query data requires only a handful of code. Given a simple VCL project with an ADO connection to the Northwind database, a TcxDBFilterControl hooked up to the EmployeeDefsQuery component, and a grid control hooked up to the EmployeeResultsQuery component, the following code is all you need:

procedure TDemoForm.FormCreate(Sender: TObject);
begin
  EmployeeDefsQuery.SQL.Text := 'Select * From Employees Where 0 = 1';
  EmployeeDefsQuery.Open;
end;

procedure TDemoForm.FetchButtonClick(Sender: TObject);
var
  SqlStatement, WhereClause: string;
begin
  EmployeeResultsQuery.Close;
  SqlStatement := 'Select * From Employees';
  WhereClause := EmployeeFilterControl.FilterText;
  if WhereClause <> '' then
    SqlStatement := SqlStatement + ' Where ' + EmployeeFilterControl.FilterText;
  EmployeeResultsQuery.SQL.Text := SqlStatement;
  EmployeeResultsQuery.Open;
  if EmployeesTableView.ItemCount = 0 then
    EmployeesTableView.DataController.CreateAllItems;
end;

Our database engine is not fully SQL compliant, plus there were some niceties that our previous report query builder supported that had to be preserved (such as not requiring the end-user to use the % mask character with LIKE conditions). While crafting custom SQL from the filter control is not trivial, it is entirely possible and we were able to meet all of our requirements with this very useful control.

To create your own SQL from the supplied filter control, you’ll need to parse the TcxFilterControl.Criteria.Root property. The items within the criteria list can either be criteria items or additional criteria lists (TcxFilterCriteriaItem and TcxFilterCriteriaItemList). The item lists have a BoolOperatorKind property, while the criteria items have an Operator property, along with additional properties, that allow you to fully inspect the filter specified in the filter control and create your own SQL statement. While this is outside the scope of this post, feel free to contact me for more details on how to accomplish this.

I love being surprised by existing controls, new to me, that DevExpress has provided in their suites, allowing me to get my job done better and faster without additional investments in time and money. To be honest, when I thought visual query builder, I just did not think DevExpress. To me this is a showcase control (as seen from other vendors), but DevExpress’s implementation provided everything we needed to get our new report query builder going in no time.

A License for Tide

•July 18, 2009 • Leave a Comment

I’ve had some really good communications with Ron Grove concerning tide. After expressing some interest in the project, I sent him the source code for tide and the Northwind client, which prompted some discussion of the licensing I’d be using for the project.

After a couple of nights reading about many different licensing options, and some great advice from Ron, I think I’ve finally settled on using the FreeBSD/Simplified BSD license. This seems like the least restrictive copyleft license that maintains GPL compatibility. I was also considering MS-PL, but this is not GPL compatible. Now, I don’t personally think that’s a huge stopping point, but I figured if I can use a GPL compatible license, why not?

Hopefully this licensing choice will suit all who wish to download, examine, learn from, use, and possible even modify or redistribute tide. I’ll be wrapping up the second part of the customers plugin soon, and hope to have a blog post up about that this weekend.

Thanks to Ron for helping with my licensing questions!

tide.Northwind.Customers – Part 1

•July 11, 2009 • 5 Comments

We’ll be breaking the work on the Customers plugin into one or more posts. This first post will net us a working plugin for browsing and editing customers, creating new customers, and deleting customers. This is pretty easy to do using tide – we only need to implement a few of the framework’s interfaces.

However, to keep these posts from getting too long or detailed, we’ll stop at editing our customers within the DevExpress GridControl. The application will be fully functional in this respect, but I’m not a huge fan of editing data directly in a grid – I think it’s handy at times, but for the most part is confusing for end users.

In a follow up post on our Customers plugin, we’ll implement a few more interfaces that allow us to get a details window that displays docked to the right of our browse window. We’ll be able to use that screen to edit our customers, with the rest of the flow working similarly to the way it does in this post.

So, let’s get started.

As with our previous plugins, we’ll add a new project to our existing Northwind solution, specifying a Hydra Plugin Module. To our new plugin module project (Northwind.Customers), we’ll add a new Hydra Visual Plugin. This gives us a Control with a visual design surface. To our visual design surface we’ll add a DevExpress RibbonControl and a DevExpress GridControl. We’ll add a tab, group, and button to our Ribbon control – the tab and group will have a “Customers” caption, and the button will display “Browse Customers”.

Then, we’ll use the Add New Datasource wizard in Visual Studio to add a data source for the Customers table in the Northwind database. This is outside of the scope of this post, but is fairly straight forward. Then, we’ll bind our GridControl to a binding source that is associated with a customers table adapter.

And that’s it for the form design – now we’ll write some code (don’t worry – not too much).

Switching to our source code, we’ll add the following to our using clause:

using tide.PluginInterfaces;
using tide.Utilities.Plugins;

The first namespace gives us access to the interfaces we’ll be implementing. The second namespace gives us access to a base Visual Plugin class from which we’ll inherit our current plugin. We’ll call our visual plugin BrowsePlugin, and adjust it’s declaration:

public partial class BrowsePlugin : MasterWindow, IRibbonProvider, IPrintableProvider

The MasterWindow class is declared in tide.Utilities.Plugins, and does some nice things for us, such as automatically saving and restoring DevExpress GridControl customizations, LayoutControl changes, and providing default implementations for IMasterWindow. IMasterWindow allows the controls in the host’s Quick Access Toolbar and Application Menu (items for saving changes, creating new items, deleting items) to interact with our plugin. Implmenting IRibbonProvider allows us to surface our Ribbon in the host. Finally, IPrintableProvider allows us to make controls within our plugin printable and exportable via the host’s Application Menu.

First, we’ll override several of the IMasterWindow methods that are implemented in the MasterWindow class:

public override string ItemName()
{
    return "Customer";
}

public override bool NewItemEnabled()
{
    return true;
}

public override void NewItem(object refId)
{
    customersBindingSource.AddNew();
}

public override bool SaveItemEnabled()
{
    return northwindDataSet.HasChanges();
}

public override bool SaveItem()
{
    customersTableAdapter.Update(northwindDataSet.Customers);
    return true;
}

public override void DeleteItem()
{
    customersBindingSource.RemoveCurrent();
}

public override bool DeleteItemEnabled()
{
    return customersBindingSource.Position = 0;
}

These very simple methods allow the Quick Access Toolbar and items in the host’s Application Menu to interact with our plugin.

Next, we’ll implement IRibbonProvider:

public DevExpress.XtraBars.Ribbon.RibbonControl RibbonControl()
{
    return ribbonControl1;
}

And now IPrintableProvider:

public DevExpress.XtraPrinting.IPrintable Printable()
{
    return gridControl1;
}

Now, we’ll add the meat of the code for this plugin. We need to add a couple of namespaces for access to our settings and encryption:

using tide.Utilities.Settings;
using tide.Utilities.Encryption;

Then, we’ll add a Click handler for the Browse Customers button on our RibbonControl, and handle it with the following code:

private void barButtonItem1_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
    BrowseNorthwindCustomers();
    ((IHostApplication)Host).DisplayPlugin(this);
}

private void BrowseNorthwindCustomers()
{
    string connectionString = GetConnectionString();
    customersTableAdapter.Connection.ConnectionString = connectionString;
    customersTableAdapter.Fill(northwindDataSet.Customers);
    customersView.BestFitColumns();
}

private string GetConnectionString()
{
    ApplicationSettings applicationSettings = new ApplicationSettings((IHostApplication)Host);
    SimpleSettings simpleSettings = new SimpleSettings(applicationSettings.SettingsFileName);
    SimpleEncryption.PassPhrase = "northwindpassphrase";

    string connectionString = simpleSettings.GetSetting("Northwind/ConnectionString", "");
    if (connectionString != "")
        connectionString = SimpleEncryption.SimpleDecrypt(connectionString);

    return connectionString;
}

And that’s it! No sweat broken, I hope. As with our previous examples, we are really just implementing some very simple methods and interfaces from the tide framework. Running the application now lets us browse customers, create new customers, make changes to existing customers (with the Save items in the host’s Quick Access Toolbar and Application Menu enabling as necessary), and save those changes. We can also print our customers, and export them to Excel, Acrobat, and several other formats.

tide.Northwind

In our next post, we’ll update this Customers plugin module, disallowing inline editing in the GridControl and creating a new Hydra Visual Plugin that implements IDetailWindow, allowing us to view the details of a selected customer and make changes within that dedicated screen.

A Few New Articles

•July 11, 2009 • Leave a Comment

I’ve posted a couple of new articles – one on creating Data Abstract servers utilizing RemObjects Hydra, and one on creating custom packages for your Hydra projects. I’ve also added links to a few of my other articles available in the links section on the right.

Hopefully I can keep the motivation going and get a new post on tide up.

What is tide?

•July 1, 2009 • Leave a Comment

To call tide an application framework is, in my humble opinion, an overstatement. Even the term plugin framework seems like a bit much – after all, that’s what RemObjects Hydra is.

Perhaps scaffolding is a better term – or is that only for user interfaces generated from DB’s?

So what is tide?

The bits and pieces that make up tide will be:

  • A great starting point for many .NET applications that will make use of DevExpress WinForms controls and RemObjects Hydra
  • A sort of working tutorial on how the myriad of DevExpress controls interact at an application level
  • The completed Northwind client will serve as a nice sort of “mega-demo” for both the DevExpress WinForms controls and RemObjects Hydra for .NET

So, now, what should you expect from the completed Northwind client? My plans are to provide:

  • A working application for editing the customers and orders in Northwind, including the usual CRUD functionality
  • A functioning options plugin for setting up the Northwind connection
  • Browse and detail screens screens for viewing, searching, and filtering customers and orders
  • A sample registration plugin, written in Delphi, to illustrate incorporating software registration and using RemObjects Hydra to load plugins from Delphi

And, over time, who knows what else may creep in – scope creep is okay in demos no?

Of course, as discussed before, because this uses the tide framework (someone please give me a better word!), this all comes with “automatic” support for great controls from DevExpress, including the Ribbon from Microsoft’s Fluent Interface, live spell-checking, printing, exporting to various file formats, Visual Studio 2008-style docking, runtime layout customization, and much more.

More importantly, the demo should illustrate that all of this functionality comes (from DevExpress and RemObjects really), at very little cost in terms of source code written and maintained. Most of these features come from supporting one or two methods of an implemented interface.

More to come soon. Have a great 4th of July, if I don’t find time to post beforehand!

How Do You Take Notes?

•June 30, 2009 • 4 Comments

How do you take notes? For years I’ve used (or tried to) OneNote on my desktop. And for the past six months or so, I’ve been using NoteBook.app on my laptop.

I’ve never really loved OneNote. I can’t really put my finger on exactly why, but I think it’s because OneNote doesn’t really do anything to help me keep my notes organized. Between notebooks and tabs and pages and unfiled notes, my OneNote notes end up just as cluttered as text files lying around my desktop (both physically and digitally).

I liked the more rigid structure of NoteBook.app – you can write on lined paper, with categories and tabs, but far more organized than OneNote. Plus there are lots of niceties, such as being able to make a note a to-do item with a keystroke, and then easily search your notebook for finished or unfinished to-do items.

However, the big, big, BIG downside to both of these – no syncing. I now work at home on a Windows 7 box, on my work laptop which is a Macbook, and I also do light work away from both on my phone. Finally, last week, when I was sitting down to transcribe physical notes into a digital copy, I went searching for something better.

Helllooooooo Evernote. How have I missed out on these tool? First of all, it’s free. Second of all, the OS X application is very, very well done. There is a Windows application as well, which is – well – good enough. And there’s an iPhone application which is very nice with lots of animations and pretties.

But on top of that, my notes now sync effortlessly between my desktop, laptop, phone, and the web. There’s a very serviceable web interface to my notes at evernote.com, and I am also able to publish any of my notebooks online, either publicly or opting to invite individuals via email.

I’ve only been using Evernote for a few days, but I’m really pleased so far. There are some font oddities, and some weirdness with nested bullets in notes authored in the Windows software. But all-in-all, I’d highly recommend Evernote. I’ve pulled NoteBook.app off my dock, and unpinned OneNote from my Windows 7 taskbar.

Do You Remember Project Dionysus?

•June 26, 2009 • Leave a Comment

In mid-2002, Project Dionysus set out to revolutionize the Delphi developer toolset. Project Dionysus was to deliver a package of third-party solutions for Delphi that would allow a developer to augment their Delphi Professional license and – it was claimed – end up with more functionality, for a lower price, than Delphi’s Enterprise SKU.

Key players in the Project Dionysus lineup were Report Builder (reporting), RemObjects SDK (web services and remoting), ExpressQuantumGrid (grid suite), ExpressWeb Framework (ASP.NET competitor), DXSock (internet connection components), and a suite of database access layers.

Was the endeavor successful? Who knows (the companies involved most likely).

But it was a big win for myself both personally and professionally. I had already had experience with DevExpress when rumors of Dionysus first surfaced, but the project further solidified my interest in and commitment to their toolset (then VCL, now much more).

Project Dionysus was also the first time I had heard of RemObjects SDK. That was a life saver. This was, I believe, during their beta phase for version 1, and we decided to leverage RemObjects SDK for our web services at a mobile electronics startup. Without going into details, this was probably one of the single best decisions I’ve made in my professional career.

Thank you, Project Dionysus. Your hype machine exposed me to two of my favorite vendors – now two of the most relevant players – in the development tools market.

tide.Northwind.Connection

•June 25, 2009 • 3 Comments

So tide – it stands for Technician Integrated Data Environment. Technician is a project name with some history for me, and the name tide itself has been with this project since day one.

The next plugin we create for this Northwind demo, following our branding provider, will be a connection plugin. After adding another new Hydra Plugin Module project, we’ll add a Hydra Visual Plugin (as opposed to the Non-Visual Plugin we created previously). We’ll add the same tide.PluginInterfaces assembly reference and namespace, this time opting to implement tide.PluginInterfaces.IOptionsPage.

The tide host application has a built in options dialog. This dialog resembles the Office 2007 options dialog. Any Visual Plugins that implement IOptionsPage have a category button added for them on the left hand side of the options dialog, and surface the functionality necessary in the host’s options dialog in order to display a page of preferences, loading and saving settings as necessary.

Our Northwind connection plugin will also make use of a few classes in the tide.Utilities namespace. These classes allow for very simple encryption, decryption, serialization and de-serialization of application settings.

The connection plugin will also use the Microsoft.Data.ConnectionUI.Dialog assembly. This is a simple way for us to provide a visual interface for defining a SQL server connection.

Our complete IOptionPage implementation is as simple as this:

private SimpleSettings simpleSettings;
private SqlConnectionProperties connectionProperties;

public void LoadOptions()
{
    SetupSettingStorage();

    string connectionString = simpleSettings.GetSetting(
        "Northwind/ConnectionString", "");
    if (connectionString != "")
        connectionString =
            SimpleEncryption.SimpleDecrypt(connectionString);
    connectionProperties.ConnectionStringBuilder.ConnectionString =
        connectionString;

    sqlConnectionUIControl1.Initialize(
        connectionProperties);
    sqlConnectionUIControl1.LoadProperties();
}

private void SetupSettingStorage()
{
    ApplicationSettings applicationSettings =
        new ApplicationSettings((IHostApplication)Host);
    simpleSettings = new SimpleSettings(
        applicationSettings.SettingsFileName);
    connectionProperties = new SqlConnectionProperties();
    SimpleEncryption.PassPhrase = "northwindpassphrase";
}

public bool SaveOptions()
{
    string connectionString =
        connectionProperties.ConnectionStringBuilder.ConnectionString;
    simpleSettings.SetSetting("Northwind/ConnectionString",
        SimpleEncryption.SimpleEncrypt(connectionString));
    return true;
}

public bool SaveOptionsEnabled()
{
    return true;
}

public string Caption()
{
    return "Northwind Connection";
}

Running the tide host application with our new connection provider plugin should display a new page in the application options dialog:

Options (9)

Keep an eye out for the next tide blog post, which will cover the first steps in creating a plugin for viewing, editing, adding, deleting, and saving customer changes within the Northwind database (it’s only a handful of code). Without having to write any additional source, this plugin will have the ability to print customers and export customer lists to XLS, PDF, and more.