![](CodinginTiers1/auto1.jpg)
Introduction
This article is the first in the two part series, and demonstrates a technique to auto-populate Windows Forms using an Automator
class. The articles presented in this series will be as follows.
- Coding in Tiers - Part I (Automate UI Form population)
- Coding in Tiers - Part II (Reuse code in Windows and Web forms)
The downloadable source and executable code provided includes the example application. I am using Visual Studio .NET 2003 with Framework SDK 1.1 to create this example.
Patterns, Levels, Layers and Tiers
Enterprise solutions should not only be highly available and scalable, but also flexible and reusable to adapt to rapidly changing business requirements. Designing reusable software is not an easy task. It is relatively easy to write not so reusable software than designing and writing software which consists of reusable components. While the former may be a good idea for prototyping, it does not serve us well in the long run. Software designed with reuse in mind is very powerful since it saves a lot of precious time (and thus cost) in developing and debugging code when it can be readily "plugged-in".
Design Patterns occupy center stage when it comes to software component reusability. A Pattern describes a recurring problem that occurs in a given context, and based on a set of guiding forces recommends a solution. Patterns make software flexible, elegant and thus reusable. Patterns exist at many different levels of abstraction. Each of these levels can be thought of as being a cluster of design patterns.
![](CodinginTiers1/auto2.jpg)
Each level could consist of multiple layers e.g. Presentation, Services, Business, Data Access etc. A layer consists of elements at roughly the same level of abstraction. The dependencies in each layer have to be identified to formulate a layering strategy. Building applications without a good strategy for dependency management leads to brittle and fragile components, which are difficult and expensive to maintain, extend, and substitute. If the levels can be thought of as being laid out vertically, the layers would be laid out horizontally. This results in a matrix consisting of cells that define and use proven software design patterns. Each layer from the infrastructure viewpoint has a corresponding tier which in a multi-tier architectural model could be classified as follows...
- Client Tier - All devices or system clients accessing the application e.g. Windows Application, Web Browser etc.
- Presentation Tier - Components that provide an user interface (UI) for performing business logic.
- Services Tier - Abstraction of services provided by the application which communicate with the business tier.
- Business Tier - Components that perform business logic and transactions.
- Integration Tier - Components that communicate with an external resource such as a data store.
- Resource Tier - Contains business data which is accessed by the integration tier.
Best Practices
Separating disparate code is the key to successful implementation of a well structured application. Keep the code closer to the tier which it needs to interact with. Components that create a user interface and perform user interaction should be factored into the Presentation tier while components that perform database inserts, updates and queries should be a part of the Integration tier. Tight coupling between tiers result in code which is difficult to maintain and reuse. For e.g. consider a windows application which presents a user interface for registering a user in the system. If the code in the Business tier were to use a component from the Presentation tier, a problem could arise when the user interface was changed from a windows form to a web form.
using System.Windows.Forms;
namespace Win
{
public class AutoForm : System.Windows.Forms.Form
{
private void SaveButton_Click(object sender, System.EventArgs e)
{
AccountManager.Register(this);
}
}
public sealed class AccountManager
{
public static void Register(AutoForm form) {
}
}
The code for AccountManager
above will not compile without a reference to System.Windows.Forms.dll. This problem can be solved by extracting the reusable code out into a class library and creating a new class State
that holds all the information entered into the user interface via the use of properties as shown in the code snippet below.
using System.Windows.Forms;
using Lib;
namespace Win
{
public class AutoForm : System.Windows.Forms.Form
{
private State state = new State();
private void SaveButton_Click(object sender, System.EventArgs e)
{
AccountManager.Register(this.state);
}
}
}
using System.Web.UI;
using Lib;
namespace Web
{
public class AutoForm : System.Web.UI.Page
{
private State state = new State();
private void SaveButton_Click(object sender, System.EventArgs e)
{
AccountManager.Register(this.state);
}
}
}
using System;
namespace Lib
{
public class State
{
}
public sealed class AccountManager
{
public static void Register(State state) {
}
}
The dependency on the AccountManager
can be eliminated by providing an additional service tier as we will see in the follow up article. Every property defined in the State
class depends on the type of control used on the UI i.e. A TextBox
would be represented as a string
where as a CheckBox
should be represented as a bool
. However, there is one more problem. The instance of State
needs to be populated with values from the UI in the SaveButton_Click()
method of the AutoForm
class (Windows Application or ASP.NET Web Application). We will limit our discussion to the Windows Application for this article.
Introducing Automator
The SaveButton_Click()
method would look something similar to the code snippet shown below.
private void SaveButton_Click(object sender, System.EventArgs e)
{
this.state.Username = usernameTextBox.Text;
this.state.Subscribe = subscribeCheckBox.Checked;
AccountManager.Register(state);
}
Assuming that there is a LoadButton_Click()
method for loading the last stored state of the form; The LoadButton_Click()
method would look something similar to the code snippet shown below.
private void LoadButton_Click(object sender, System.EventArgs e)
{
usernameTextBox.Text = this.state.Username;
subscribeCheckBox.Checked = this.state.Subscribe;
}
This could be cumbersome and error-prone especially when using complex forms which house a lot of controls. What we need is a utility class "Automator"
which automatically stores and restores the state of the form. A skeletal code snippet describing its usage is shown below.
namespace Win
{
public class AutoForm : System.Windows.Forms.Form
{
private Automator automator;
public AutoForm
{
automator = new Automator(this, this.state);
}
private void SaveButton_Click(object sender, System.EventArgs e)
{
automator.Store();
AccountManager.Register(this.state);
}
private void LoadButton_Click(object sender, System.EventArgs e)
{
automator.Restore();
}
}
}
Great! But how will this happen? This is done by using the magic of reflection. The property names on the State
are matched with the names (case-sensitive) of controls on the form whose state is to be saved. The Store()
method on the Automator
class will iterate over all the controls contained within the form matching the name of every control to the property on the State
object. If a match is found, the value on the control is set on the matching property after applying type conversion (if necessary). The Restore()
method on the Automator
class will work in exactly the reverse order i.e. populating the control with the value from the matching property.
Control Name |
Control Type |
Property Name |
Property Type |
Username |
System.Windows.Forms.TextBox |
Username |
string |
Subscribe |
System.Windows.Forms.CheckBox |
Subscribe |
bool |
Interests |
System.Windows.Forms.ListBox |
Interests |
string[] |
Closing Note
This article demonstrates a technique to auto-populate a Windows Form. My next article will abstract some of the code out to make it more flexible and reusable. We will introduce a new Service tier in addition to the Presentation and Business tiers described in this article. The follow up article will demonstrate code reusability in three different types of applications viz. Windows, Web and Web Services.
References/Links