Click here to Skip to main content
Click here to Skip to main content

Coding in Tiers - Part I

, 14 Sep 2003
Rate this:
Please Sign up or sign in to vote.
Automate UI Form population

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.

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; // Windows Forms

// Windows Application
namespace Win
{
    // Windows Form
    public class AutoForm : System.Windows.Forms.Form
    {
        // Members

        // Store the state of the form
        private void SaveButton_Click(object sender, System.EventArgs e)
        {
            // Register a new user
            AccountManager.Register(this);
        }
    }

    // A class to manage user accounts
    public sealed class AccountManager
    {
      // Register a new user
      public static void Register(AutoForm form) { // Process Registration }
    }
}

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.

// Windows Application
using System.Windows.Forms; // Windows Forms

using Lib; // For the AccountManager and Registration class

// Presentation Tier (Windows)
namespace Win
{
    // Windows Form
    public class AutoForm : System.Windows.Forms.Form
    {
        // The registration information
        private State state = new State();

        // Members

        // Store the state of the form
        private void SaveButton_Click(object sender, System.EventArgs e)
        {
            // Populate state with values from the UI controls
            AccountManager.Register(this.state);
        }
    }
}

// ASP.NET Web Application
using System.Web.UI; // Web Forms

using Lib; // For the AccountManager and Registration class

// Presentation Tier (Web)
namespace Web
{
    // Web Form
    public class AutoForm : System.Web.UI.Page
    {
        // The registration information
        private State state = new State();

        // Members

        // Store the state of the form
        private void SaveButton_Click(object sender, System.EventArgs e)
        {
            // Populate state with values from the UI
            AccountManager.Register(this.state);
        }
    }
}

// Class Library
using System;

// Business/Domain Tier
namespace Lib
{
    // A class to hold registration information
    public class State
    {
        // Properties corresponding to the controls on the UI
    }

    // A class to manage user accounts
    public sealed class AccountManager
    {
        // Register a new user
        public static void Register(State state) { // Process Registration }
    }
}

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.

// Store the state of the form
private void SaveButton_Click(object sender, System.EventArgs e)
{
    // Store TextBox value
    this.state.Username = usernameTextBox.Text;

    // Store CheckBox value
    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.

// Restore the state of the form
private void LoadButton_Click(object sender, System.EventArgs e)
{
    // Restore TextBox value
    usernameTextBox.Text = this.state.Username;

    // Restore CheckBox value
    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
{
    // Windows Form
    public class AutoForm : System.Windows.Forms.Form
    {
        // Members

        // The form automator
        private Automator automator;

        public AutoForm
        {
            automator = new Automator(this, this.state);
        }

        // Store the state of the form
        private void SaveButton_Click(object sender, System.EventArgs e)
        {
            // Store the state using the automator
            automator.Store();
            // Register the user
            AccountManager.Register(this.state);
        }

        // Restore the state of the form
        private void LoadButton_Click(object sender, System.EventArgs e)
        {
            // Restore the state using the automator
            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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Salil Pitkar
Web Developer
United States United States
Over 15 years of experience in designing and architecting high availability/scalability financial application software using OO technologies such as C++/Java/C#.

Comments and Discussions

 
GeneralMy vote of 5 Pinmemberonurag195-Jan-13 10:39 
GeneralNice article ! PinmemberSébastien Lorion15-Sep-03 0:54 
GeneralRe: Nice article ! PinmemberSalil Pitkar15-Sep-03 11:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.1411023.1 | Last Updated 15 Sep 2003
Article Copyright 2003 by Salil Pitkar
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid