Programmer to ProgrammerTM  
Wrox Press Ltd  
   
  Search ASPToday Living Book ASPToday Living Book
Index Full Text
 
ASPToday Home
 
 
Home HOME
Site Map SITE MAP
Index INDEX
Full-text search SEARCH
Forum FORUM
Feedback FEEDBACK
Advertise with us ADVERTISE
Subscribe SUBSCRIBE
Bullet LOG OFF
                         
      The ASPToday Article
April 6, 2001
      Previous article -
April 5, 2001
  Next article -
April 9, 2001
 
   
   
   
An overview of .NET winforms   Benny JohansenJan Narkiewicz  
by Benny Johansen, Jan Narkiewicz
 
CATEGORY:  .NET Framework  
ARTICLE TYPE: Overview Reader Comments
   
    ABSTRACT  
 
Article Rating
 
   Useful
  
   Innovative
  
   Informative
  
 53 responses

This article is the first of a series discussing client-side development using .Net Windows Forms (WinForms). Most web developers do not delve into this dark art known as traditional client-side development. However over the last couple of years, and especially with the introduction of .NET, the distinction between pure web development and pure client-side development has been blurred considerably. Using WinForms you can easily develop a functionally and graphically rich application.

   
                   
    Article Discussion   Rate this article   Related Links   Index Entries  
   
 
    ARTICLE

Introduction

This article is the first of a series discussing client-side development using .Net Windows Forms (WinForms). Most web developers do not delve into this dark art known as traditional client-side development. However over the last couple of years, and especially with the introduction of .NET, the distinction between pure web development and pure client-side development has been blurred considerably. Using WinForms you can easily develop a functionally and graphically rich application. This type of application may be used to access web services or maybe used for the administration of an Internet site. WinForms could also be used to develop controls used by web applications.

This article introduces WinForms development by demonstrating a simple Windows Application that exposes a form. Remember that WinForms falls under the purview of .Net. WinForms applications can therefore be developed using C#, VB.Net, C++ or any language that supports application development under .Net. The application in this article is written using C# with a Visual Basic implementation found in Appendix A. Visual Basic developers should however find the main body of this article quite readable. This is because the majority of the article discusses how to use Visual Studio .Net to develop a WinForms application. The majority of the code is written in Visual Studio .Net's WinForms Designer.

The form presented in this article contains a Button, CheckBox and TextBox control. The material covered by this article includes:

Basic Windowing fundamentals (message, message loops, etc.) will be reviewed in the context of the .Net Framework. Where applicable the various features of the .Net Framework and C# will be presented.

Future articles in this series will cover menus, property and form inheritance, custom controls, property pages and GDI+. Each article is based on the lessons learned while developing our traditional, client-side administrative application.

MSDN has also documented WinForms with articles such as, "Using the Microsoft .NET Framework to Create Windows-based Applications" (http://msdn.microsoft.com/library/techart/netwinforms.htm?WROXEMPTOKEN=1643539ZIzmWc8pTuCEPmrWcfR) and "Creating Designable Components for Microsoft Visual Studio .NET Designers" (http://msdn.microsoft.com/library/techart/pdc_vsdescmp.htm?WROXEMPTOKEN=1643539ZIzmWc8pTuCEPmrWcfR). Be aware that these articles pre-date the release of Visual Studio .Net Beta 1.

Windows Applications and WinForms Basics

A basic WinForms application is constructed using controls. According to MSDN, a control is a "component with visual representation." Translated from MSDN-speak to English, controls are small windows that perform common tasks. Take for example the button. Buttons have been around for decades. WinForms provides a button object (control). A button is pressed and action is taken. A button has a variety of appearances. The following is a partial list of the controls available to a WinForms application:

Each object in the WinForms hierarchy exposes the following types of members:

An entire list of the WinForms object hierarchy is quite extensive and can be found at: http://msdn.microsoft.com/library/techart/netwinforms.htm?WROXEMPTOKEN=1643539ZIzmWc8pTuCEPmrWcfR

A WinForms application is created using Visual Studio .Net and selecting the New menu item in the File menu. Then select the Project sub-menu item. Selecting this option reveals the following dialog:

Image

Under the Project Types category, click on Visual C# Projects and select from the Templates category the Windows Application project. Visual Basic developers would select Visual Basic projects instead. Notice in the previous dialog that the name of the Windows application was specified as SWPWinForm00 . This is our introductory WinForms project hence the 00 . Our consulting firm, Software Pronto Inc., uses the prefix, SWP, (www.softwarepronto.com). Any project, source file, namespace or class prefixed by SWP is not a native feature to .Net and was not written by Microsoft.

The source file created by default for a Windows Application is Form1.cs and contains the form1 class. From Visual Studio .Net's solution explorer, the file name Form1.cs was renamed to SWPForm00.cs by right clicking on the file name. Double clicking on the file displays the form on which WinForm's control will be placed. Double clicking on the form reveals the source code associated with the form (the source code associated with SWPForm00.cs ). Visual Studio's .Net's Edit menu's Find and Replace menu item has a Replace sub-menu item and that was used to change the name of the class from Form1 to SWPForm00 .

The content of the source file, SWPForm00.cs, demonstrates certain features of .Net and how these features integrate with C#. The functionality of .Net is divided up into Assemblies. Each Assembly contains a set of types wrapped up in a Namespace. A namespace provides a way of grouping classes and a mechanism for limiting the visibility of a class. A namespace can insure that every class of every Assembly is not globally visible by name. The System.WinForms.Dll assembly contains objects wrapped in the System.WinForms namespace. In order to access the contents of this namespace and others the source file, SWPForm00.cs, contains the following C# using statements:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.WinForms;
    using System.Data;

All the namespaces listed previously are provided by default when a C# or VB.Net windows application is developed using Visual Studio .Net. Particular attention should be paid to the System namespace. This namespace is the backbone of .Net defining among other things the fundamental types of the .Net common language runtime, which include Char, String, Int32, UInt32 and Array .

C#'s using directive can save typing time for a developer. Consider WinForm's class, Button . When declaring a Button it can be fully qualified (namespace and class name):

    System.WinForms.Button button1;

Fully qualifying a type contained in a namespace is tedious. The using directive allows a button or any other type found in System.Winforms to be declared without the namespace qualifier. Any namespace qualified with the using directive can be omitted when referring to a type contained in that namespace. The following code snippet demonstrates an alternative declaration of a Button object without the qualifying namespace:

    Button button1;

Assemblies in Visual Studio must be referenced. Visual Basic developers are familiar with COM type reference libraries. This concept of a reference is analogous to C/C++ linking with a DLL's import library. Each Assembly specified in our application (see previous code snippet) is already referenced by the project associated with application, SWPForm00 . Using Visual Studio's Solution Explorer we can see that we already referenced System.WinForms in addition to other assemblies:

Image

For a Visual Studio .Net windows application, System.WinForms is a default Assembly to reference.

The class, SWPForm00, is defined as follows:

    public class SWPForm00 : System.WinForms.Form
    {
        private System.ComponentModel.Container components;

        public SWPForm00()
        {
            // Required for Windows Form Designer support
            InitializeComponent();
        }

        public override void Dispose()
        {
            base.Dispose();
            components.Dispose();
        }

        /// <summary>
        ///    Required method for Designer support - do not modify
        ///    the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.Size = new System.Drawing.Size(300,300);
            this.Text = "SWPForm00";
        }

        public static void Main(string[] args) 
        {
            Application.Run(new SWPForm00());
        }
    }

Some things of interest in class SWPForm00 are:

The WinForms namespace contains a class called Form . The Form class is derived from the following base classes:

    Object
        MarshalByRefObject
            MarshalByRefComponent
                Control
                    RichControl
                        ScrollableControl
                            ContainerControl
                                Form

The InitializeComponent method includes the following line of generated code:

    this.Text = "SWPForm00";

The Text property, this.Text, is inherited from the Control base class found in the namespace System.WinForms . The Text property is set to specify the text currently associated with the control. In the case of a form, this is the text displayed above the form. For demonstration purposes, change the string text in the previous code snippet from SWPForm00 to Hello World . Now, build the Windows application, SWPWinForm00 (Visual Studio's Build menu's Build item) and run the application.

Remember that the documentation generated by Visual Studio .Net states that the InitializeComponent method, should not be edited directly by the developer. We have just committed an egregious sin that we are destined to repeat. We should have used Visual Studio's Properties Window to edit this information (more on this later).

Controls Properties

There are a large number of properties associated with the Form class from which our class, SWPForms00, is derived. These properties include:

The Form class has many more properties. These properties can be set programmatically as we saw in the InitializeComponent method. Each of these properties has a default value. The majority of the Properties are therefore not set programmatically. In general, a more detailed examination of the code in the source file, SWPForm00.cs, could be made. Recall that Visual Studio .Net is in its first Beta stage. There is a chance that the code generated could change in the final release of the product so an intricate review is not merited at this time.

Now that we have examined the source code of an empty Form, it is time to add controls to the Form. In a .Net Windows Application, controls are dragged onto a Form using the WinForms Designer. The WinForms Designer is displayed by accessing the Visual Studio .Net's View menu's and clicking the Designer menu item. The WinForms Designer window for the SWPForm00 application is as follows

Image

From Visual Studio's View menu, select the Properties menu item. The following will be displayed within Visual Studio:

Image

By modifying the properties associated with the form, we can change the code in the InitializeComponent method. Using the properties dialog we could change the BackColor property to Magenta and text property could be changed from Hello World to Hi mom! Visual Studio would update the method as follows:

    this.Text = "Hi mom!";
    this.BackColor = System.Drawing.Color.Magenta;

Basic Child Controls (Button, Text Box and Check Box)

Once a Windows Application is created, use the Visual Studio .Net View menu to display the WinForms Designer and the Toolbox. The following screenshots shows the WinForms Designer and the Toolbox (note: the background color of the form has been changed from Magenta back to White):

Image

Image

In the previous screenshot the right mouse button was used to select and drag three Controls: a button, Textbox and a Checkbox. These WinForm controls are declared as the data members of the class, SWPForm00 . These variables are declared as follows:

    private System.WinForms.TextBox textBox1;
    private System.WinForms.CheckBox checkBox1;
    private System.WinForms.Button button1;

Recall that the WinForms Designer uses the InitializeComponent method to initialize each WinFrom control. These controls were added by dragging the appropriate control from the ToolBox to the Form associated with the SWPForm00 class. The code associated with setting up the control type of the Button is as follows:

    this.button1 = new System.WinForms.Button ();
    button1.Location = new System.Drawing.Point (88, 24);
    button1.Size = new System.Drawing.Size (75, 23);
    button1.Text = "button1";

The Button, button1, is created using the C# new operator. For button1, the Location property is specified to be 88 pixels to the right of the left edge of the form and 24 pixels from the top of the form. The Location is specified using the Point structure found in the namespace System.Drawing . The size of the button is 75 pixels in width and 23 pixels in height. The Text property is set to button1.

The button-related code in the InitializeComponent method, can be configured using Visual Studio's Properties window. The properties for each control on the form are displayed using the Properties Window. In the following screenshot, the Properties Windows is displayed in conjunction with the WinForms Designer. The following screenshot shows the Properties Windows that would be displayed with the designer:

Image

When the properties for button1 are displayed, changes made to the properties value will be reflected in the source code. Using the Properties Window, the text associated with the button, button1 can be changed from button1 to Show Message . The new text does not fit on the Button in its present form. Using the WinForms Designer, button1 was stretched so that the Button was wide enough to display Show Message . The Properties Window that changed the Text property of button1 is shown below:

Image

The code associated with setting up the control type CheckBox is as follows:

    this.checkBox1 = new System.WinForms.CheckBox ();
    checkBox1.Location = new System.Drawing.Point (104, 112);
    checkBox1.Text = "checkBox1";
    checkBox1.Size = new System.Drawing.Size (120, 24);

The checkbox, checkBox1, is set up identically to button1 . First the checkbox is allocated using new . Once checkBox1 is created, the Location, Text and Size properties are set.

The code associated with setting up the control type TextBox is as follows:

    this.textBox1 = new System.WinForms.TextBox ();
    textBox1.Location = new System.Drawing.Point (104, 72);
    textBox1.Text = "textBox1";
    textBox1.Size = new System.Drawing.Size (100, 20);

Once textBox1 is created using the C# new operator, the Location, Text and Size properties are set.

There is code that associates each control with a tab order when the form's window is in focus and the tab key is pressed. The tab order is: Button to CheckBox to TextBox . The order specified is like this because each Control has a Property, TabIndex, (button1 is TabIndex=0, checkBox1 is TabIndex=1 and textBox1 is TabIndex=2). The code in the InitializeComponent method associated with the tab order is as follows:

    button1.TabIndex = 0;
    checkBox1.TabIndex = 1;
    textBox1.TabIndex = 2;

Modifying the code in the method, InitializeComponent, can change the tab order. The tab order can also be changed using the properties of each specific control.

Recall that the class, SWPForm00, is derived from the class, Form . In turn the Form class is derived from the Control class, . A control class contains a controls collection. The control collection contains the child controls associated with the form. The controls collection is a standard .Net collection; therefore it exposes an Add method to add a new child control to the entry. The child controls associated with form, SWPForm00, are: button1, checkBox1 and textBox1 . The code in the method, InitializeComponent that adds the child controls is as follows:

    this.Controls.Add (this.textBox1);
    this.Controls.Add (this.checkBox1);
    this.Controls.Add (this.button1);

The Form for the Windows Application, SWPForm00, was modified slightly from the defaults. The Text Property associated with textBox1 was ultimately set to be an empty string by default. The Text Property associated with checkBox1 was set to Show user message . The width of this Checkbox was stretched to display the Text on a single line. These changes are reflected as follows:

Image

Controls: Events

Below is another screenshot of Visual Studio's WinForms Designer (left hand portion of the screenshot) and the Properties Window (right-hand portion of the screenshot):

Image

Notice above that the Properties windows shows the Events associated with the Checkbox, checkBox1 rather than the Properties associated with this control. This is because the icon containing the lightning bolt was selected. The icons that ran along the top of the Properties Windows are defined as follows, in the order appearing in the screenshot:

Image

At this stage we would like to handle events. Scrolling down through the events associated with checkBox1, one event of interest that sticks out is CheckedChanged . This event will fire when the state of the Checkbox changes from checked-to-uncheck and from unchecked-to-checked. Notice in the screenshot below that CheckedChanged is highlighted in dark blue:

Image

In the previous screenshot, the white area to the right of this highlighted region is where a developer can enter the name of a method that will be called when the event, CheckedChanged, is fired by the CheckBox control on the Form. Double clicking on the white area causes Visual Studio to generate the code associated with an event handler. This code generation includes adding to the class, SWPForm00, a method named, checkBox1_CheckedChanged :

    protected void checkBox1_CheckedChanged(object sender, 
                                                System.EventArgs e)
    {
    }

This code could have been generated using another technique. From the WinForms Designer double click on the checkBox1 control. The WinForms Designer will generate the event handler for the CheckedChanged event.

The method, checkBox1_CheckedChanged, is not the only change made to the source file SWPForm01.cs in order to handle the Event, CheckedChanged . In the method, InitializeComponent, the WinForms Designer added the following line of code:

    checkBox1.CheckedChanged+= 
        new System.EventHandler (this.checkBox1_CheckedChanged);

Here we have created a new object of type EventHandler from System Namespace. This object will call our checkBox1_CheckedChanged method when the state of the CheckBox changes. The EventHandler object is actually a Delegate. A Delegate is used to represent what we would like a particular method to look like (the method prototype). For the case of the EventHandler delegate this means our method must:

The method generated by Visual Studio, checkBox1_CheckedChanged, conforms to the prototype specified by the Delegate EventHandler.

The other event of interest to our application is when the button is Clicked. The simplest way to generate a method capable of handling this event is to double click on the button as it is displayed in the Forms designer. Double clicking works for only the most common events responded to by a WinForms control. The majority of the events (those least commonly used) require a few more steps. The longer way of generating a method capable of handling the button click event is as follows:

The code generated when the following steps are performed is as follows:

    protected void button1_Click (object sender, 
                                  System.EventArgs e)
    {
    }

Implementation

The methods generated to handle events have as yet no code. Now is the time to make our application do something. Our initial idea was to develop a Windows Application that solves worldwide hunger and brings peace to every corner of the world. This was deemed slightly too complicated a topic for this forum, so instead the Windows Application, SWPForm00 performs the following steps

Determining whether to display or hide textBox1 is determined each time the state of checkBox1 is changed. The following code shows the Checked property of checkBox1 being examined. Based on the Checked property, the Visible Property of textBox1 is set to either true or false . The following code snippet demonstrates this behavior:

    protected void checkBox1_ CheckedChanged(object sender, 
                                                 System.EventArgs e)
    {
        if (checkBox1.Checked)
        {
            textBox1.Visible = true;
        }

        else
        {
            textBox1.Visible = false;
        }
    }

Determining whether or not to display a default message or a user-entered message is handled as follows:

    protected void button1_Click (object sender, 
                                  System.EventArgs e)
    {
        if (checkBox1.Checked)
        {
            string strTextOut = "Button pressed (user entered text): ";

            strTextOut += textBox1.Text;
            MessageBox.Show(strTextOut);
        }

        else
        {
            MessageBox.Show("Button pressed -- this is the default text");                
        }
    }

If the Checked Property of checkBox1 is true, a user-entered message is displayed. This user-entered method is retrieved from the Text Property of TextBox, textBox1 . If the Checked Property of checkBox1 is false, a default text string is displayed.

Control Methods

Our implementation relied on only the Properties and Events associated with each control. However methods also exist for each control. For example a Button object can click itself programmatically by calling the method, PerformClick .

Each control presented ( Button, CheckBox and TextBox ) is derived from the Control class. The Control class exposes the Hide method. The method, Hide, makes a control invisible by setting the Visible Property of the control to false . The code associated with the method, checkBox1_CheckedChanged, could have been written as follows in order to use a method to hide the text box rather than a Property (see code below highlighted using boldface):

    protected void checkBox1_ CheckedChanged(object sender, 
                                             System.EventArgs e)
    {
        if (checkBox1.Checked=true)
        {
            textBox1.Visible = true;
        }

        else
        {
            textBox1.Hide();   
        }
    }

Conclusions

Ninety percent of user-interface design is Buttons, Checkbox's, List Box's and other such controls. This article presents the basics of how to get started with WinForms. Using these basics we developed a simple form and used the properties, methods and events associated with simple controls. This article also scratches the surface of the rich development environment included with the .Net Framework by introducing such concepts as assemblies, namespaces, projects, solutions and delegates.

The WinForms development process is similar in look-and-feel to the Visual Interdev or Visual Basic 6.0 development environment. With WinForms, Microsoft has improved the object model and moving to .Net has clear advantages including easy installation/deployment, better security, simpler memory management and cross-platform development. Clearly the questions is not if you will move to WinForms but when you will take advantage of this exciting object hierarchy and its solid development tool, Visual Studio .Net.

Appendix A - Visual Basic .Net Implementation

The steps to create a Visual Basic .Net version of this project were identical to the steps required to generate a C# version of the project. Remember that Visual Studio .Net generated the vast majority of the project's code. The code in the methods checkBox1_CheckedChanged and button1_Click was translated from C# to Visual Basic .Net

Public Class SWPFunVB
    Inherits System.WinForms.Form
    
    Public Sub New()
        MyBase.New()
        
        SWPFunVB = Me
        
        'This call is required by the Win Form Designer.
        InitializeComponent()
        
        'TODO: Add any initialization after the InitializeComponent() call
    End Sub
    
    'Form overrides dispose to clean up the component list.
    Public Overrides Sub Dispose()
        MyBase.Dispose()
        components.Dispose()
    End Sub
    
#Region " Windows Form Designer generated code "
    
    'Required by the Windows Form Designer
    Private components As System.ComponentModel.Container
    Private WithEvents CheckBox1 As System.WinForms.CheckBox
    Private WithEvents TextBox1 As System.WinForms.TextBox
    Private WithEvents Button1 As System.WinForms.Button
    
    Dim WithEvents SWPFunVB As System.WinForms.Form
    
    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container()
        Me.CheckBox1 = New System.WinForms.CheckBox()
        Me.Button1 = New System.WinForms.Button()
        Me.TextBox1 = New System.WinForms.TextBox()
        
        '@design Me.TrayHeight = 0
        '@design Me.TrayLargeIcon = False
        '@design Me.TrayAutoArrange = True
        CheckBox1.Checked = True
        CheckBox1.Location = New System.Drawing.Point(96, 120)
        CheckBox1.Text = "Show User Message"
        CheckBox1.Size = New System.Drawing.Size(136, 24)
        CheckBox1.CheckState = System.WinForms.CheckState.Checked
        CheckBox1.TabIndex = 2
        
        Button1.Location = New System.Drawing.Point(96, 24)
        Button1.Size = New System.Drawing.Size(104, 23)
        Button1.TabIndex = 0
        Button1.Text = "Show Message"
        
        TextBox1.Location = New System.Drawing.Point(96, 80)
        TextBox1.TabIndex = 1
        TextBox1.Size = New System.Drawing.Size(100, 20)
        Me.Text = "Hi Mom!"
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        
        Me.Controls.Add(CheckBox1)
        Me.Controls.Add(TextBox1)
        Me.Controls.Add(Button1)
    End Sub
    
#End Region
    
    Protected Sub CheckBox1_CheckedChanged(ByVal sender As Object, _
                                           ByVal e As System.EventArgs)
        If True = checkBox1.Checked Then
            textBox1.Visible = True
            
        Else
            textBox1.Visible = False
        End If
    End Sub
    
    Protected Sub Button1_Click(ByVal sender As Object, _
                                ByVal e As System.EventArgs)
        If True = checkBox1.Checked Then
            Dim strTextOut As String = _
                        "Button pressed (user entered text): "
            
            strTextOut += textBox1.Text
            MessageBox.Show(strTextOut)
            
        Else
            MessageBox.Show("Button pressed -- this is the default text")
        End If
        
    End Sub
    
    Protected Sub SWPFunVB_Click(ByVal sender As Object, _
                                 ByVal e As System.EventArgs)
        
    End Sub
    
End Class
 
 
   
  RATE THIS ARTICLE
  Please rate this article (1-5). Was this article...
 
 
Useful? No Yes, Very
 
Innovative? No Yes, Very
 
Informative? No Yes, Very
 
Brief Reader Comments?
Your Name:
(Optional)
 
  USEFUL LINKS
  Related Tasks:
 
 
   
  Related ASPToday Articles
   
  • Reflection API in .NET framework (August 23, 2001)
  • .NET Windows Forms Menus (May 23, 2001)
  • .NET Windows Forms Inheritance (April 24, 2001)
  •  
           
     
     
     
           
      Search the ASPToday Living Book   ASPToday Living Book
     
      Index Full Text Advanced 
     
     
           
      Index Entries in this Article
     
  • .NET Framework
  •  
  • Add method
  •  
  • Application object
  •  
  • assemblies
  •  
  • BackColor property
  •  
  • Button controls
  •  
  • C#
  •  
  • checkbox controls
  •  
  • Control class
  •  
  • controls
  •  
  • controls collection
  •  
  • event handling
  •  
  • form class
  •  
  • Hide method
  •  
  • implementing
  •  
  • InitializeComponent method
  •  
  • introduction
  •  
  • Location property
  •  
  • namespaces
  •  
  • NEW keyword
  •  
  • object model
  •  
  • Run method
  •  
  • Size property
  •  
  • Solution Explorer
  •  
  • text box controls
  •  
  • text property
  •  
  • Toolbox
  •  
  • using
  •  
  • using directive
  •  
  • VB.Net
  •  
  • Visual Studio.Net
  •  
  • web controls
  •  
  • WinForms
  •  
  • WinForms Designer
  •  
     
     
    HOME | SITE MAP | INDEX | SEARCH | REFERENCE | FEEDBACK | ADVERTISE | SUBSCRIBE
    .NET Framework Components Data Access DNA 2000 E-commerce Performance
    Security Admin Site Design Scripting XML/Data Transfer Other Technologies

     
    ASPToday is brought to you by Wrox Press (http://www.wrox.com/). Please see our terms and conditions and privacy policy.
    ASPToday is optimised for Microsoft Internet Explorer 5 browsers.
    Please report any website problems to webmaster@asptoday.com. Copyright © 2001 Wrox Press. All Rights Reserved.