Click here to Skip to main content
15,881,559 members
Articles / Programming Languages / C#
Article

Using inheritance to create Windows Forms dialogs.

Rate me:
Please Sign up or sign in to vote.
3.47/5 (16 votes)
27 Jul 20034 min read 57.5K   905   32   4
The article demonstrates how to create a base class for Windows Forms dialogs.

Introduction

Every time we need a new dialog in our applications, we have to do all the same things over and over again. We have to create a new descendant of the System.Windows.Forms.Form class, change a whole bunch of properties through property grid, place a couple of buttons on the form, make a decision on how to pass data in and out of the dialog, and find a proper place for initialization and completion code. Although, all this is not a big deal, doing it all over again is quite boring and seems to be nothing but just plain waste of time. In this article, we will try to create a base class for modal dialogs.

If you have any experience in programming with Borland Delphi, you are probably familiar with "visual inheritance" concept. This technology existed for years in Delphi products and proved itself to be a useful and very powerful feature. You also may know that using visual inheritance in Delphi is sometimes quite tricky. The problems grow from Delphi's model of forms and components persistence. Fortunately, Visual Studio .NET stores all the properties through code and this makes Windows Forms classes no different from any other class in .NET framework. We can easily create more specialized derivatives of System.Windows.Forms.Form class and use them as a base in our .NET applications.

Creating Dialog class

This is the simplest part of the job. All we need to start is a new form and two Button controls on it (named btnOk and btnCancel). Having this done, we'll use property grid to change the form's properties as shown below:

C#
this.Controls.AddRange(new System.Windows.Forms.Control[] 
   { this.btnCancel, this.btnOk });    
this.AcceptButton = this.btnOk;
this.CancelButton = this.btnCancel;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Dialog";
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Dialog";

Note that, both buttons have their modifier property set to protected. This will allow us to change behavior or even hide these buttons in derived classes. After this, our dialog looks like this:

Passing data in and out

In a typical scenario, a modal dialog accepts some data from its application, processes it and then returns the modified data back to the caller. Although, there is nothing difficult in passing data to the dialog, it would be useful to have a unified solution for data transfer operations. We'll start unification with the definition of an abstract base class, which is going to be an ancestor for all data transfer classes.

C#
public class DialogData
{
    public static readonly DialogData Empty = new DialogData();
        
    public DialogData()
    {
    }
}

As you may notice, this class is very similar to the standard System.EventArgs class. Our DialogData has almost the same purpose, with only one exception - EventArgs transfers data in and out of event handlers and DialogData transfers data in and out dialogs boxes. Now, we have to decide how to pass the data to the dialog and how to get it back. We could create a special constructor accepting an instance of DialogData, but in some cases, the same instance of a dialog may be used many times before it gets disposed with different data associated with each call. System.Windows.Forms.Form class provides an overloaded ShowDialog() method, which seems to be a good match for our data object, as it gets called every time we need our dialog to be shown. So, we have to create new versions of this method and add some new overloads:

C#
public new DialogResult ShowDialog()
{
    return this.ShowDialog(null, null);
}
        
public new DialogResult ShowDialog(IWin32Window owner)
{
    return this.ShowDialog(owner, null);
}
        
public DialogResult ShowDialog(DialogData data)
{
    return this.ShowDialog(null, data);
}
        
public DialogResult ShowDialog(IWin32Window owner, DialogData data)
{            
    this.data = data;

    DialogResult result = base.ShowDialog(owner);
    return result;
}

Initializing and finishing dialog

The Dialog class is almost complete. One more thing we'll definitely need is a place for dialog's initialization and finishing code. This can be easily accomplished with events. First, we we'll create two new System.EventArgs descendants for InitDialog and FinishDialog events.

C#
/// Provides data for InitDialog event.
public class InitDialogEventArgs
{
    private DialogData data = null;

    /// Initializes a new instance of the InitDialogEventArgs class 
    /// with the Data property set to null.
    internal InitDialogEventArgs()
    {
    }

    /// Initializes a new instance of the InitDialogEventArgs class 
    /// with the Data property set to the given value.
    internal InitDialogEventArgs(DialogData data)
    {
        this.data = data;
    }        
        
    /// Gets data object associated with the event.
    public DialogData Data
    {
        get{ return data; }
    }
}


/// Provides data for FinishDialog event.
public class FinishDialogEventArgs
{
    private DialogData data = null;
    private DialogResult result;

    /// Initializes a new instance of the FinishDialogEventArgs class 
    /// with the Data property set to null and
    /// Result property set to the given value.
    internal FinishDialogEventArgs(DialogResult r)
    {
        result = r;
    }        

    /// Initializes a new instance of the FinishDialogEventArgs class 
    /// with the Data and Result properties set to the given values.
    internal FinishDialogEventArgs(DialogData data, DialogResult r)
    {
        this.data = data;
        result = r;
    }        

    /// Gets data object associated with the event.
    public DialogData Data
    {
        get{ return data; }
        set{ data = value; }
    }
    
    /// Gets a return value of a dialog box.
    public DialogResult Result
    {
        get{ return result; }
    }
}

InitDialogEventHandler and FinishDialogEvent handlers are declared as follows:

C#
public delegate void 
  InitDialogEventHandler(object sender, InitDialogEventArgs e);
public delegate void 
  FinishDialogEventHandler(object sender, FinishDialogEventArgs e);

InitDialogEventArgs class exposes a new property called Data which is always set to the value passed to ShowDialog() as data parameter. InitDialogEventArgs has the same Data property and a DialogResult property of type System.Windows.Forms.DialogResult. The latter always has a value that will be returned to a caller as a result of a call to ShowDialog() method. We can use this value to make a decision whether we should modify the Data object or discard any changes made to the dialog. Finally, we'll add protected methods that fire InitDialog and FinishDialog events and complete the implementation of ShowDialog() method.

C#
public DialogResult ShowDialog(IWin32Window owner, DialogData data)
{    
    this.data = data;
    OnInitDialog(new InitDialogEventArgs(this.data));


    DialogResult result = base.ShowDialog(owner);


    OnFinishDialog(new FinishDialogEventArgs(this.data, result));
    return result;
}
    
protected virtual void OnInitDialog(InitDialogEventArgs e)
{
    if(InitDialog != null)
        InitDialog(this, e);
}

protected virtual void OnFinishDialog(FinishDialogEventArgs e)
{
    if(FinishDialog != null)
        FinishDialog(this, e);
}

Using the Dialog class

Demo project provided with this article shows how we may use our Dialog class to create a very simple login dialog.

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


Written By
Web Developer
Russian Federation Russian Federation
Working as a sr. software developer for a large company based in St.Petersburg, Russia.

Comments and Discussions

 
QuestionLicense information? Pin
Member 103749191-Nov-13 6:49
Member 103749191-Nov-13 6:49 
GeneralVery useful sample!!! Pin
MBB34-Dec-07 23:15
MBB34-Dec-07 23:15 
GeneralMore to be added Pin
jmelgaard9-Sep-07 20:43
jmelgaard9-Sep-07 20:43 
GeneralWell done!!! Pin
Brutes14-Jun-04 20:22
Brutes14-Jun-04 20:22 

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

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