Click here to Skip to main content
11,567,814 members (42,062 online)
Click here to Skip to main content

Part I: Unifying Web and Windows Form design and layout

, 9 Jul 2002 211.8K 3.7K 117
Rate this:
Please Sign up or sign in to vote.
Part I of a multipart series, it illustrates how to unify GUI design for both Web Forms and Windows Forms, so that a single GUI specification can be rendered in both technologies.

Editors Note: the source code files have a hard coded path so ensure that the demo and source files are unzipped to the root directory of your C: drive with folder names turned on so the proper directory structure is created.

<!-- Add the rest of your HTML here -->

Introduction

One of the selling points of VS.NET is the ability to share a common data source such as a database with both Windows client applications and Web applications. Thus, VS.NET provides GUI capability through the System.Web.UI.WebControls namespace and the System.Windows.Forms namespace.

Unfortunately, VS.NET requires that you design each GUI separately for the two respective technologies. Furthermore, naming conventions, usage, and GUI controls are slightly different between the two technologies. This all results in a complicated development effort, probably supported by two separate teams, which in itself increases the complexity of developing a product that supports both technologies.

This article demonstrates a methodology for unifying these two technologies. By using a resource file, the same GUI can be generated in Window Forms or Web Forms. To demonstrate this capability, I have taken a GUI from an actual product currently being developed in VC++ 6.0. I have ported the GUI over to C# and demonstrate several GUI components supported both in Web Forms and Window Forms. The GUI is one component of several that manages inventory, work orders, labor, and billing for a boat yard here in beautiful Stonington, CT.

This article is Part I of a several part series in which I demonstrate a unified framework for Web Forms and Window Forms development. Following will be:

Part II: An interface layer for GUI events

This article will delve into handling GUI events through an interface layer. Because the dynamic forms classes do not let you derive controls, and thus implement event handlers within the child classes, an interface layer must be used to handle events. Part II will enhance the demonstration program in Part I by adding events.

Part III: Interfacing with control data and managing data lifetime

As with events, dynamically generated controls need an interface layer for storing and retrieving data. This issue is complicated by the Web Forms environment, which "forgets" all application wide data whenever a page is loaded. This issue is addressed here so that Web Forms and Window Forms operate seamlessly to the application logic. Part II will enhance the demonstration program in Part II by adding data management capabilities.

Part IV: Decoupling the database schema from the application schema

Application, or 'business logic' should not mirror the database schema, as this creates redundancy. In this part, I introduce a generalized method for interfacing with a database, building on the data management techniques discussed in Part III. Part IV will enhance the demonstration program in Part III by completing the application so that customer information can be stored and retrieved from the database.

Why Support Both Web Forms and Windows Forms?

The primary reason for supporting Web Forms is remote access capability, the ability for the customer (in my case, the business) to access their operations from a browser. Management might wish to do this in order to check on the status of a work order, and accounting may wish to view inventory usage, etc.

So the question is, why not have the in-house personnel use a browser also? I would say that there are two reasons: a Windows Forms application can be customized in ways that a Web Forms application can't (or at least not easily), and secondly, performance. A Windows Forms application can maintain application-wide data, whereas a Web Forms application must save this information and retrieve it whenever the page is reloaded. Furthermore, this information is session specific, making things a bit more complicated. In the program being developed for the boatyard, there isn't a lot of application-wide data, but what there is, is very useful for performance reasons.

Limitations

I have not implemented all GUI controls, especially such things as tab controls, style sheets, trees, etc. There are some GUI elements that simply don't translate from web browser to Window application. However, I expect to update this technology frequently and will post updates when they become available. Also, some of the cosmetics of the GUIs are poorly implemented, and I intend to keep working on these as well.

The IDynControl Interface

The integration of these two technologies is accomplished with a straight forward object model design, as illustrated in the diagram at the beginning of the article.

IDynControl is an interface class that is inherited by DynWindowControl and DynWebControl. These two classes serve as base classes for each technology-specific control (illustrated as DynWindow and DynWeb in the UML diagram at the top of the page). The purpose of these two base classes is essentially to provide implementations to common and shared functionality of all controls in each of the respective technologies. The child classes implement any control specific functionality.

The implementation of IDynControl is straight forward:

namespace dynFormLib
{
    public interface IDynControl
    {
        void AddEvent(System.EventHandler ev);

        System.Windows.Forms.Control GetWindowCtrl();
        System.Web.UI.Control GetWebCtrl();

        string GetCaption();
        string GetAttribute();
        uint GetStyle();
        void SetCaption(string caption);
        void SetAttribute(string attribute);
        void SetStyle(uint style);
    }
}

It includes some placeholders for future features, and specifies to very important methods:

GetWindowCtrl()
GetWebCtrl()

These methods return the object instantiated for the specific technology, which is used internally in the form manager. The application (whether a Web Form or Windows Forms application) should never use these methods to directly manipulate a control unless there is a very specialized requirement to do so. Instead, the application should use the IDynControl interface class for control manipulation. This class can be expanded to provide the necessary symmetrical implementations for both Web Forms and Window Forms.

The DynWebControl Class

The DynWebControl is the base class for all classes that encapsulate Web controls. As you can see from the code, it incorporates some standard initialization in the Create method and defines default behavior for the abstract methods in the interface class. This is especially useful, because we probably won't need specific implementations of the interface class methods for each control. Note especially how the GetWindowCtrl() and GetWebCtrl() methods are handled. Also note that this class encapsulates the base class for all web controls: System.Web.UI.WebControls.WebControl. Ultimately, because of implementation differences, the GetCaption() and SetCaption() methods have to be handled by the specific child classes--for some reason, the Text property is not a member of the web control base class, whereas it is in the window control base class. Go ask Microsoft.

public class DynWebControl : IDynControl
{
    public virtual System.Windows.Forms.Control GetWindowCtrl() 
        { return null; }
    public virtual System.Web.UI.Control GetWebCtrl() 
        { return ctrl; }

    public virtual void Create(int x, int y, int sx, int sy,
        string text, string name)
    {
        ctrl.Style["POSITION"] = "absolute";
        ctrl.Style["LEFT"] = x.ToString() + "px";
        ctrl.Style["TOP"] = y.ToString() + "px";
        ctrl.Style["WIDTH"] = sx.ToString() + "px";
        ctrl.Style["HEIGHT"] = sy.ToString() + "px";
        ctrl.Font.Size = 9;
        ctrl.Font.Name = "MS Sans Serif";
    }

    public virtual void AddEvent(System.EventHandler ev) {}
    public virtual string GetCaption() { return ""; }
    public virtual string GetAttribute() { return ""; }
    public virtual uint GetStyle() {return 0;}

    public virtual void SetCaption(string s) {}
    public virtual void SetAttribute(string s) {}
    public virtual void SetStyle(uint style) {}

    protected System.Web.UI.WebControls.WebControl ctrl;
}

The DynWindowControl Class

The DynWindowControl is very similar to the DynWebControl class, as illustrated:

public class DynWindowControl : IDynControl
{
    public virtual System.Windows.Forms.Control GetWindowCtrl()
        { return ctrl; } 

    public virtual System.Web.UI.Control GetWebCtrl() 
        { return null; }

    public virtual void Create(int x, int y, int sx, int sy,
        string text, string name)
    {
        ctrl.Location=new Point(x, y);
        ctrl.Size=new Size(sx, sy);
        ctrl.Text=text;
        ctrl.Name=name;
    }

    public virtual void AddEvent(System.EventHandler ev) {}
    public virtual string GetCaption() { return ctrl.Text; }
    public virtual string GetAttribute() { return ""; }
    public virtual uint GetStyle() { return 0; }

    public virtual void SetCaption(string s) { ctrl.Text=s; }
    public virtual void SetAttribute(string s) {}
    public virtual void SetStyle(uint style) {}

    protected System.Windows.Forms.Control ctrl;
}

An Example Control Implementation

I'll use a button as an example of a control created for both Web and Window Forms. The Web Form control is implemented as follows:

public class DynWebButton : DynWebControl
{
    public override void Create(int x, int y, int sx, int sy,
        string text, string name)
    {
        ctrl = new System.Web.UI.WebControls.Button();
        ((System.Web.UI.WebControls.Button)ctrl).Text = text;

        base.Create(x, y, sx, sy, text, name);
    }
}

This is a very simplistic implementation, and doesn't offer any of the rich set of styles, etc., that buttons can have. This is true for all of the controls implemented in the source code. I plan on expanding this capability.

The button control for the Window Form is implemented as follows:

public class DynWindowButton : DynWindowControl
{
    public override void Create(int x, int y, int sx, int sy,
        string text, string name)
    {
        ctrl = new System.Windows.Forms.Button();
        base.Create(x, y, sx, sy, text, name);
    }
}

Note the similarity in implementation.

The IDynForm Interface

As you may have guessed, the System.Windows.Forms.Form is also derived using a class that interfaces with IDynForm.

public interface IDynForm
{
    void AddControl(IDynControl ctrl);
}

In the current prototype, there is no similar construct for web forms, so the derived class simply interfaces with IDynForm directly. This interface class has only one method: AddControl. This is used by the application to add an IDynControl object to the form. Because the form "knows" whether it is a Web Form or Window Form, it invokes the correct Get... method, to get either the Web or Window control instance.

Loading Controls

Loading controls is currently implemented in a brute force way. In Part IV, I will change this implementation to read the "resource file" directly out of the database. Currently, a structure supports the information necessary for control creation, plus some features I will be using in later articles:

public struct ControlInfo
{
    public ControlInfo(string type, Point pos, Size size,
        string name, string text, string var, string varList)
    {
        this.type = type;
        this.pos = pos;
        this.size = size;
        this.name = name;
        this.text = text;
        this.var = var;
        this.varList = varList;
    }

    public string type;
    public Point pos;
    public Size size;
    public string name;
    public string text;
    public string var;
    public string varList;
}

Creating controls requires instantiating an array of these structures (for example): ControlInfo[] ctrlInfo=new ControlInfo[46];

An excerpt:

ControlInfo[] ctrlInfo = new ControlInfo[2];

ctrlInfo[0] = new ControlInfo("label", new Point(20, 33), 
    new Size(80, 15), "lblLastName", "Last Name:", "", "");

ctrlInfo[1] = new ControlInfo("edit", new Point(120, 30), 
    new Size(200, 20), "edLastName", "", "", "");

In Web Forms, the aspx.cs code initializes the controls and then loads the form:

DynWebForm mainForm=new DynWebForm();
mainForm.Init(Label1);
mainForm.LoadControls(ctrlInfo);
mainForm.Run();

While in Windows Forms, a very similar code set it used:

DynWindowForm mainForm=new DynWindowForm();
mainForm.Create(0, 0, 800, 600, "Dynamic Form", "dynForm");
mainForm.LoadControls(ctrlInfo);
mainForm.Run();

Note that for Web Forms, all controls are children of a label on the main form.

Conclusion

Regardless of whether the button has been created for a browser or for a Window Form, the application can now reference the control through the IDynControl interface. While this implementation is currently very simplistic, it can easily be expanded so that the application no longer need concern itself with the target technology. This considerably simplifies Web/Window Forms programming.

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

Marc Clifton
United States United States
Marc is the creator of two open source projects, MyXaml, a declarative (XML) instantiation engine and the Advanced Unit Testing framework, and Interacx, a commercial n-tier RAD application suite.  Visit his website, www.marcclifton.com, where you will find many of his articles and his blog.

Marc lives in Philmont, NY.

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
manoj kumar choubey28-Nov-12 19:35
membermanoj kumar choubey28-Nov-12 19:35 
GeneralLatest version Pin
alhambra-eidos4-Aug-08 21:27
memberalhambra-eidos4-Aug-08 21:27 
Generalright on Pin
Stas Desyatnikov21-Mar-04 10:30
memberStas Desyatnikov21-Mar-04 10:30 
GeneralRe: right on Pin
Marc Clifton21-Mar-04 10:35
editorMarc Clifton21-Mar-04 10:35 
GeneralSuggestion for the web form implementation Pin
bingwoo28-Nov-03 3:51
memberbingwoo28-Nov-03 3:51 
GeneralRe: Suggestion for the web form implementation Pin
Stas Desyatnikov21-Mar-04 10:10
memberStas Desyatnikov21-Mar-04 10:10 
GeneralRe: Suggestion for the web form implementation Pin
hell_spawn27-May-04 1:48
susshell_spawn27-May-04 1:48 
Generaltwo questions Pin
.S.Rod.5-Jan-03 5:44
member.S.Rod.5-Jan-03 5:44 
GeneralRe: two questions Pin
Marc Clifton5-Jan-03 6:01
memberMarc Clifton5-Jan-03 6:01 
GeneralRe: two questions Pin
partyganger10-Jan-04 9:46
memberpartyganger10-Jan-04 9:46 
GeneralRe: two questions Pin
Marc Clifton10-Jan-04 10:45
editorMarc Clifton10-Jan-04 10:45 
QuestionBridge Mode? Pin
Feng Qin11-Sep-02 19:07
memberFeng Qin11-Sep-02 19:07 
AnswerRe: Bridge Mode? Pin
Marc Clifton12-Sep-02 0:29
memberMarc Clifton12-Sep-02 0:29 
GeneralRe: Bridge Mode? Pin
Paul Watson7-Nov-02 3:38
sitebuilderPaul Watson7-Nov-02 3:38 
GeneralRe: Bridge Mode? Pin
peterchen1-Dec-02 2:36
memberpeterchen1-Dec-02 2:36 
GeneralToo Java-like Pin
Daniel Cazzulino15-Jul-02 2:44
memberDaniel Cazzulino15-Jul-02 2:44 
GeneralRe: Too Java-like Pin
Marc Clifton15-Jul-02 3:43
memberMarc Clifton15-Jul-02 3:43 
GeneralRe: Too Java-like Pin
Creative116-Nov-03 5:48
memberCreative116-Nov-03 5:48 
GeneralRe: Too Java-like Pin
Marc Clifton16-Nov-03 6:59
editorMarc Clifton16-Nov-03 6:59 
GeneralRe: Too Java-like Pin
Anonymous29-Aug-02 5:11
sussAnonymous29-Aug-02 5:11 
GeneralGreat approach, thanks for the article. Pin
zeroman12-Jul-02 4:21
memberzeroman12-Jul-02 4:21 
QuestionCode Missing? Pin
Anonymous10-Jul-02 6:24
sussAnonymous10-Jul-02 6:24 
AnswerRe: Code Missing? Pin
Marc Clifton10-Jul-02 9:43
memberMarc Clifton10-Jul-02 9:43 
GeneralRe: Code Missing? Pin
kgrubbs11-Jul-02 15:49
memberkgrubbs11-Jul-02 15:49 
GeneralRe: Code Missing? Pin
TomW16-Jul-02 2:46
sussTomW16-Jul-02 2:46 

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
Web04 | 2.8.150624.2 | Last Updated 10 Jul 2002
Article Copyright 2002 by Marc Clifton
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid