Skip to main content

skip to main content

developerWorks  >  Information Management  >

Using C#Builder Architect to build model-driven Windows applications for DB2 UDB

Part 2

developerWorks
Document options

Document options requiring JavaScript are not displayed


My developerWorks needs you!

Connect to your technical community


Rate this page

Help us improve this content


Level: Intermediate

Jeremy McGee (jeremy@mcgee.demon.co.uk), Independent IT Consultant

15 Jan 2004

In this two-part series, we show you how to use Borland Enterprise Core Objects (ECO) in Borland C#Builder Architect to build a powerful application for IBM DB2 Universal Database (UDB) that is powered by a UML model. This second article shows how ECO can quickly build complex user interfaces.

Introduction

Borland® C#BuilderTM Architect extends the development capabilities of C#Builder to cover model-driven development. This saves time coding business logic by automatically implementing part of a Unified Modeling Language (UML) software model.

In the first article, we looked at how the ECOTM designers and runtime framework in C#Builder Architect can help implement an application quickly. In this article, I’ll extend the simple application that we created in the first part of the article so that the user can manipulate the other object classes that we created. You’ll also see how to use the data integrity options available through associations.

A trial version of C#Builder Architect is available from the Borland Web site.



Back to top


Adding people

Our UML diagram includes two lists of people, each associated with the departments in the DataGrid that we’ve placed on the form. Next, you’ll add two grids to the form and create a simple user interface to let the user enter the personal information.

Add two more grids to the main WinForm, making them wide enough for seven columns plus the left margin. Place two buttons below these grids, and set their Text properties to be Add Employee and Add Candidate. You’ll add the program code for these buttons later.


Figure 1: The empty user interfacer
Figure 1: The empty user interface

Name each of the grids, from top to bottom, dgDepartment, dgEmployee, and dgCandidate. We’ll be referring to the current record of the Department data grid to filter the employees and candidates.

Next, you’ll set up two new ExpressionHandles that will obtain the data for these grids. This time, rather than pointing directly to the whole collection of objects, we’ll filter the names by the appropriate department. To do this you’ll need a new component, the CurrencyManagerHandle.

The CurrencyManagerHandle returns the object that a data-bound control is pointing to. So, here you can use a CurrencyManagerHandle to find which department is currently selected by the Department grid. You can also use the CurrencyManagerHandle as the root handle for an ExpressionHandle.

From the Tool Palette, select a CurrencyManagerHandle and place it on the form. Set the properties to:

Name: cmhDepartment
RootHandle: ehDepartment 
BindingContext: dgDepartment

That’s all that’s necessary. From this point on you can use the expression

(Department)cmhDepartment.Element.AsObject

to return the Department object to which the Department data grid points.

You can now set up the new ExpressionHandles for the Employee and Candidate grids. Drop two ExpressionHandles on the form and set their properties to:

Name: ehEmployee
RootHandle: cmhDepartment
Expression: employs

Name: ehCandidate
RootHandle: cmhDepartment
Expression: mightEmploy

As you’ll see, the RootHandle here is set to the CurrencyManagerHandle, not the root handle for the form. Cascading ECO handles in this way can be a very powerful technique.

Then you can set the DataSource property of each grid to point to the appropriate ExpressionHandle. Compile the application, and the columns should be completed automatically: (Note: the grids most likely won’t show the right columns until you compile.)


Figure 2: Connecting the grids to their data sources
Figure 2: Connecting the grids to their data sources

Next, add code to the two buttons so you can add contacts. For the Add Employee button, the code will look very similar to that used in the previous article to add a Department. This time, however, it’s necessary to set the department of the employee:

// Create a new Employee object
Employee theEmployee = new Employee(EcoSpace);

// Set the department of this employee to be the object selected 
// by dgDepartment
theEmployee.worksFor = (Department)cmhDepartment.Element.AsObject;

And similarly, for the Add Candidate button:

Candidate theCandidate = new Candidate(EcoSpace);

// Set the department of this candidate to be the object selected 
// by dgDepartment
theCandidate.mightWorkFor = (Department)cmhDepartment.Element.AsObject;

Notice a couple of useful features here. One is that the names used for the associations in the UML diagram (worksFor, mightWorkFor) show up as ‘properties’ of the Employee and Candidate objects. These properties return genuine, bona fide .NET objects in their own right. This makes it possible for you to use expressions like

theCandidate.mightWorkFor.Location

to find what location the candidate could work for. This can be used where, with DB2®, you’d use SELECT queries, except here you can use the native C# object types directly.

Compile the application and run it.


Figure 3: The application filters by departments
Figure 3: The application filters by departments

Make sure you have a department entered before you press either the Add Employee or Add Candidate buttons, otherwise your call to cmhDepartment.Element.AsObject will return a null object reference. A more sophisticated version of the application might check this and ‘gray out’ the buttons.

When you add an employee or candidate, you’ll see a new line open up in the appropriate data grid. Try entering two or three lines of data, then switch to another department and enter more lines of data. You should see the Employee and Candidate grids change automatically as you change the department row – this is an event that is automatically cascaded by the CurrencyManagerHandle component.



Back to top


Fine-tuning the interface

You’ll notice that there’s a column set for the worksFor and mightWorksFor properties in the Employee and Candidate grids. The only data displayed here is the name of the object – there’s no default property for a Department object, so the object name is all that’s available.

To remove this column, close the application and return to the form designer for the main WinForm. The DataGrid that we’re using is just the same as any other .NET application, so you can set properties to explicitly choose the columns you need.

Select the dgEmployee grid, and choose the TableStyles property editor (under Data). The DataGridTableStyle Collection Editor is displayed. By default this is blank: press the Add button to add a new TableStyle based on the .NET defaults.

This is where you can change the appearance of the grid – the fonts, colors, whether alternating background lines are displayed, and so forth. The .NET DataGrid allows several tables to be displayed at once, but here we’re just using one, so there’s no need to add any others.

The particular property that you’ll want to set to adjust the columns is GridColumnStyles, at the bottom under Misc. Click on the property editor and you’ll see a second, nested collection editor appear, the DataGridColumnStyle editor.

Here we can explicitly select the properties for each column in the data grid. Add a DataGridTextBoxColumn for the first column, set the HeaderText property to Name, and the MappingName property to Name. Repeat for all the columns except the worksFor column.

Close the ColumnStyle editor, then the TableStyle editor. Your grid should now look much tidier. Here I’ve reworked the column headings to include spaces to make them more readable:


Figure 4: The application, with customized columns
Figure 4: The application, with customized columns


Back to top


Adding an extra form

But what if we want to give the user a way to select the department that an employee works for through a regular Windows dialog? In this final step you’ll see how to use another WinForm in the application as a dialog box that can edit an Employee object.

The default blank ECO application that is created includes, by default, an EcoWinForm. Switch to this form, and you’ll see that it already includes RootHandle and ExpressionHandle components. We’ll use this as our dialog, and the first stage will be to save the form as GetEmployee.cs. Name the form as ewfEditEmployee and set its title to Enter Employee Details.

With this done, select the root handle rhRoot and point it to the model for the application by setting the EcoSpaceType property to HRApp.HRAppEcoSpace with the drop-down.

Note that, at a stroke, this makes the objects in the model available to ECO components on this form. If you’re accustomed to the concept of a data module in Delphi, and miss that feature in C#Builder, then many of the same capabilities of a centralized association with data can be achieved through ECOWinForms.

In this case, you’ll use the dialog to work with Employee objects only. Rather than constructing an expression handle and referring to this each time that we construct an OCL expression, we can set the default type for the root handle directly. Set the StaticValueTypeName to the class Employee through the Type Name Selector property editor:


Figure 5: The Type Name Selector for static value types
Figure 5: The Type Name Selector for static value types

With this done, the root handle itself will now expect its Element property to be an Employee object.

We can now construct the user interface. Add seven Label components, six TextBox components, a ComboBox and a Button to the form so it looks like this:


Figure 6: Basic design of the Employee dialog
Figure 6: Basic design of the Employee dialog

Set the DataBindings properties of each of the TextBox components so the Text points to the appropriate DataSource:


Figure 7: Choosing the Name property for textBox1
Figure 7: Choosing the Name property for textBox1

Now the form will automatically display the current Employee object that is referred to by the root handle of the form.

The advantage of just displaying a single record in this way is that you can now easily populate the combo box with the department names. To do this, you’ll need to use the expression handle that is already on the form. Select it, and rename it to ehDepartment.

Set the properties as you’d expect:

RootHandle: rhRoot (should already be set)
Expression: Department.allInstances

Then set the combo box properties as follows:

Name: cbDepartment
DataSource: ehDepartment
DisplayMember: Name
ValueMember: Name

Next, write the following code against the SelectedIndexChanged event for the combo box:

// Find out which object was selected
IElement selected = 
  (ehDepartment.Element as IObjectList)[cbDepartment.SelectedIndex];

if (selected == null) return;

Department selDepartment = (Department)selected.AsObject;

// Extract the employee instance from rhRoot
Employee thisEmployee = (Employee)rhRoot.Element.AsObject;
thisEmployee.worksFor = selDepartment;

Note that by default the EcoWinForm doesn’t include a reference to the assembly Borland.Eco.ObjectRepresentation, which is where IElement is defined. You’ll need to add

using Borland.Eco.ObjectRepresentation;

at the top of the source code unit before the namespace declaration.

The combo box should now update the value of the worksFor property in the Employee object that is referred to by the root handle.

Switch back to the form design, double-click the Close button, and enter the following line:

this.Close();

All that remains is to establish a way to load the GetEmployee form from the main application. A neat way to do this is to overload the constructor for the EcoWinForm itself.

If you scroll up to near the beginning of the source code unit GetEmployee.cs, you’ll see the default constructor for the form: it’s the public function ewfEditEmployee(HRAppEcoSpace EcoSpace). We’ll copy this function and add the Employee object we wish to edit as an extra parameter.

Copy the function and add the extra parameter; and before the AutoContainer line, set the root handle element. The entire function will look like this:

public ewfEditEmployee(HRAppEcoSpace ecoSpace, Employee ourEmployee)
{
	//
	// Required for Windows Form Designer support
	//
	InitializeComponent();

	// Set EcoSpace (actually stores it in rhRoot.EcoSpace)
	this.EcoSpace = ecoSpace;
	// Set root handle to employee object passed in constructor
	rhRoot.SetElement(ourEmployee.AsIObject());

	// Hook up AutoContainer provider
	new AutoContainerProvider(this, EcoSpace);
}

Now we can return to the main form, WinForm.cs. Add the following two lines to the Click handler for the Add Employee button:

ewfEditEmployee editForm = new ewfEditEmployee(EcoSpace, theEmployee);
editForm.ShowDialog();

You’ve now built a form that can edit an Employee object directly.

Compile the application and run it. When you add an employee now, the new dialog should be displayed.

As you enter data, you’ll see it appear in the grid below, indicating that you’re directly editing the object. Although this is buffered locally in memory in the EcoSpace before it is stored to DB2, you may prefer to use a ‘temporary’ Employee object in this situation.



Back to top


Conclusion

The philosophy of developing an ECO application uses object-oriented concepts throughout. These may at first appear unfamiliar to DB2 developers, but the ECO ‘handle’ approach gives a very flexible way to build applications in a more productive way than through more conventional relational database techniques.

The small application you’ve built illustrates the main concepts of ECO – how to design a model, how to persist data to DB2, and how to build a fairly complex user interface. DB2 is well suited as a backing store for ECO applications as they typically need to retrieve or store a fairly large amount of data in one operation, which DB2 excels at.



About the author

Jeremy McGee started writing applications using BASIC on the Commodore PET. He fondly remembers typesetting a book-length publication on an early Apple Mac with a refrigerator-sized laser printer attached. Since then he's variously been a DEC VAX sysadmin, a technical support engineer for Borland Paradox, and was part of the team that launched Borland Delphi in Europe. Jeremy now runs a consulting firm in Southampton, UK.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top