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.
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

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

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

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.
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

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

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

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

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.
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.
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.





