Web Design that taps into the haromny and vision of your dreams.

Windows Application Development

By on in Coding

6,676 words, estimated reading time 31 minutes.

Introduction to Programming with C# Series
  1. Introduction to Programming with C# 7
  2. C# Programming Fundamentals
  3. Introduction to Object-Oriented Programming
  4. C# Object-Oriented Programming Part 2
  5. Flow Control and Control Structures in C#
  6. C# Data Types, Variables and Casting
  7. C# Collection Types (Array, List, Dictionary, Hash Table)
  8. C# Operators
  9. Using Data in C# 7 with ADO.Net & Entity Framework
  10. LINQ: .NET Language Integrated Query
  11. Error and Exception Handling in C#
  12. Advanced C# Programming Topics
  13. Reflection in C#
  14. What Are ASP.Net Webforms
  15. Introduction to ASP.Net MVC
  16. Windows Application Development
  17. Assemblies in C#
  18. Working with Resources Files, Culture & Regions
  19. Regular Expressions in C#
  20. Introduction to XML with C#
  21. Complete Guide to File Handling in C#

This guide will give you an introduction to Windows Forms development using Visual Studio and C# and the basics of form design.

This guide will give you an introduction to Windows Forms development using Visual Studio and C# and the basics of form design.

Controls such as text boxes, buttons, checkboxes and so on, can all be added to a form by dragging and dropping from the toolbox to the form. The editor will also allow you to align multiple controls and will show you the recommended distance between controls.

When you create a new Windows Application project in Visual Studio or Visual C# Express, you are presented with a blank form in design mode. You can resize the form using the draggable corner markers and you can drag controls to the form by dragging and dropping them from the toolbox to the form.

The main areas of the Integrated Development Environment (IDE) that will be used are the form designer, code designer, control toolbox, solution explorer and the properties window. If these panels or windows are not visible in your IDE, you can access them from within the View menu. They can be set to fold away when not in use to create more design/code space and appear when you hover over the tab, or it can be 'pinned' with the pushpin icon and it will stay open in its current position.

Visual Basic Form Design
Visual Basic Form Design

Have a play with dragging components onto the form from the toolbox and add a text box. Now add a button to the form and drag it around. Notice how the editor will provide alignment markers, and how it will 'snap' to the recommended position next to the textbox.

It is very highly recommended, as well as good practice, to name all components and forms properly and meaningful. When you have a complex form, it is difficult to differentiate between Button1, Button2, Button3, TextBox1, TextBox2, TextBox3 and so on when you are coding. It much much better to give these components proper names to avoid confusion.

The recommendation is to use a three-letter prefix (lowercase) for the type of control (e.g. btn for Button, txt for TextBox, lbl for Label and so on) followed by a meaningful name (e.g. btnSubmitData, txtUsername or lblPasswordReminder). You should also rename the form to frmMain or an appropriate name for the function of the form.

You can rename components by changing the (Name) property in the properties window.

I have named the button btnShowMessage and the text box txtUserInput. You should also give the button a caption that is meaningful, so find the property called Title and type in "Show Message".

The most used feature of the ID is the properties and Events window. Events will be covered in more detail in a later tutorial, but for the purposes of Windows Forms, an event is called when the user does something, e.g. Clicks a button, this will fire the Click event of the button. Events in Windows applications are automatically wired up, you do not have to do any special coding. Events can be automatically wired up in one of two ways. You can double-click a component, which will auto-wire the components default event (Default button event is the Click event, Default form event is Load). The other method is to select the component and select events from the Properties window. This will list all the events associated with that control, to wire up an event simply double-click the event which will load up the code editor with the event wired up for you.

Visual C# Properties Window
Visual C# Properties Window

Let's continue our simple demo program, double click on the button and you will a new function in the code:

private void btnShowMessage_Click(object sender, EventArgs e)
{
 
}

Into this function, we shall show a message box containing the data entered in the text box.

MessageBox.Show(txtUserInput.Text);

When run, this will show a message box with the string entered into the text box.

Auto Code Generation

When you place a button or a textbox (or any other component) onto a form, an instance of an object is created for you. At the top of the code viewer, you may have noticed two dropdown boxes. These allow you to quickly navigate through your methods, events and classes. If you drop down the right-hand box, select the InitializeComponent method. This will take you to a hidden region in the code that contains the code added by Visual Studio. You should be able to locate two lines that create a text box and button.

this.btnShowMessage = new System.Windows.Forms.Button();
this.txtUserInput = new System.Windows.Forms.TextBox();
 

Because we are creating an instance of classes defined by Microsoft, they all inherit certain methods and properties. All objects will have a ToString method, and all controls will have an ID and Name among other items. Input elements will have a Text or Value property, all clickable items (Button, Checkbox, Radio button and so on) will have a click event. Default values are setup in the InitializeComponent method, you can add or modify these items.

A little lower down, you should be able to find a line that hooks up the click event to a click function, such as the one shown below.

this.btnShowMessage.Click += new System.EventHandler(this.btnShowMessage_Click);

You do not have to worry about any of these automatically generated code sections and they have hidden away from you, but you should still be familiar with the concepts.

Now we are going to add another button under our existing button, named btnUpdateTextBox with a title of Update. Double click on the button to add the event and enter the code below:

txtUserInput.Text = "Hello World"

Now when you run the program, you can type some text into the box and press the first button to see a message dialogue with the contents of the text box and press the second to update the contents of the text box.

List Boxes and Tree Views in C#

Tree's, Lists and Grids are all very good ways of presenting data to the user, and they each have their own particular uses.

We have already seen list boxes briefly and now we will have a closer look at the list box and how to use it. All of these controls are data aware, that is they can be bound to a data source. We will have a look at Grids when we look at using data on Windows forms.

List Boxes and Combo Boxes

List boxes are used whenever you need to display a collection of items in a list format. If space is limited you can use a dropdown (combo) box instead. Both listBox and comboBox have the same methods for accessing the list items.

Adding and Removing Items

You can use the IDE interface to add items to a list, however, it is often required that we add items, or delete items, at runtime.

ListBox.Items.Add("Text to Show");

The add method will add a new item to the bottom of the list. You can use the Insert method to add an item at a specific location on the list, 0 will add the item as the first item.

ListBox.Items.Insert(5,"Text to Show");

Each item on a list box has an ItemIndex property to denote its position. The first item of the list has an ItemIndex of 0 (zero).

You can remove items from the list using the RemoveAt method, where you specify the index of the item to delete.

ListBox.Items.RemoveAt(5);

You can clear a list of all items using clear.

ListBox.Items.Clear();

Accessing Items and Selections

You can access an individual item through the Items collection to read and write items.

ListBox.Items[2] = "Hello World";
string myString = ListBox.Items[0];

Iterating through Items

There are two main methods for iterating through the items in the list, using a for and a for each loop.

for (int i = 0; i < listBox.Items.Count - 1; i++)
{
  MessageBox.Show(listBox.Items[i].ToString());
}

Because the listBox component accepts elements of any type, you must specify the type within the for each statement.

foreach (string O in listBox.Items)
{
  MessageBox.Show(O);
}

In both cases the Items collection is read-only, so cannot be assigned to.

Tree Views

Tree views are an organised list view the same as the Windows Explorer folder list view. It separates a list into sections that have subsections and so on. Like list and combo views, items can be added to a TreeView using the inbuilt IDE designer, and they can be modified at runtime. Unlike lists where an element is called an Item, each element of the tree is known as a Node.

To add a simple node to a Treeview

 TreeNode node = new TreeNode();
node.Name = "nodNewNode";
node.Text = "My New Node";
 
treeView1.Nodes.Add(node);
 

You can also add sub nodes to a node or to the tree view by creating a new TreeNode object for each item.

List Boxes and Tree Views in C#
List Boxes and Tree Views in C#
TreeNode node = new TreeNode();
node.Name = "nodNewNode";
node.Text = "My New Node";
 
TreeNode node2 = new TreeNode();
node2.Name = "nodNewNode2";
node2.Text = "My New Sub Node (a)";
node.Nodes.Add(node2);
 
TreeNode node3 = new TreeNode();
node3.Name = "nodNewNode2";
node3.Text = "My New Sub Node (b)";
node.Nodes.Add(node3);
 
treeView1.Nodes.Add(node);

If you try and reuse a node object after adding it to the tree view you will end up changing the items already assigned to the tree, as the TreeNode object is a reference type.

List Boxes and Tree Views in C#
List Boxes and Tree Views in C#
TreeNode node = new TreeNode();
node.Name = "nodNewNode";
node.Text = "My New Node";
 
TreeNode node2 = new TreeNode();
node2.Name = "nodNewNode2";
node2.Text = "My New Sub Node (a)";
node.Nodes.Add(node2);
 
node2.Name = "nodNewNode3";
node2.Text = "My New Sub Node (b)";
node.Nodes.Add(node2);

Nodes can be removed from the list using the Remove method and passing in the node you wish to remove.

treeView1.Nodes.Remove(node2);

If the above examples of node2 and node3 are not in scope you can Find a node by its name and remove it that way.

TreeNode[] nodes = treeView1.Nodes.Find("nodNewNode3", true);
foreach (TreeNode oldnode in nodes)
{
  treeView1.Nodes.Remove(oldnode);
}

This method will also delete all sub-nodes of the selected node, so if you passed in "nodNewNode" it would delete that node and the two sub-nodes and you will be left with an empty tree.

You can also remove nodes by specifying an index and using the RemoveAt method as described above.

Iterating through Items

From time to time it may be necessary to iterate through a tree view object. The only way to loop through tree view nodes is to use a recursive algorithm.

private void processNode(TreeNode node)
{
  MessageBox.Show(node.Text);
 
  foreach (TreeNode subnode in node.Nodes)
    processNode(subNode)
}
 
private void Test()
{
  foreach (TreeNode n in treeView1.Nodes)
  {
    processNode(n);
  }
}

Using Common Dialogue Boxes in C#

Visual Studio and Visual C# provide dialogue boxes for common tasks such as Open, Save and Print. In this tutorial, we will have a look at some of the dialogue boxes and see how we can load and save data in our program.

The common controls are listed under the Dialogues tab of the toolbox. You will have to drag these onto the grey area beneath the form editor, as they are non-visual components.

We are going to create menus and buttons for Open, Save and Save As. We will also need to add some simple logic to our program to detect modifications to the text. We will also look at the form closing events.

Add menu items for Open, Save and Save As to the menu strip we created in the last tutorial. You may wish to separate items with a horizontal line in order to group items of similar function. You can do this by just entering a - (minus symbol) to the text of an item, it will then change to a breaker bar. Don't forget to name each item appropriately.

There is a standard convention that should be observed regarding menu items which open a dialogue or another form, they should always end with an ellipses (three dots) to indicate another window will appear. For example "Save As...".

You should also set keyboard shortcuts to common tasks (such as Ctrl+C for Copy) and hotkeys for each time (Alt+Letter). Hotkeys are assigned by adding an ampersand before the letter, so "Save As" would become "Save &As". This will appear on the menu as "Save As".

My menu now looks like the image on the right, you can see the how separators group the menu items, and the shortcut and hotkeys.

While we are adding menu items you can also create a Format menu after the File menu with submenus for Bold, Italic and Underline and assign the events we created in the last tutorial. If you wish, you can assign icons to the menu items in exactly the same way as we add images to the toolbar buttons in the last tutorial.

Notepad Lite File Menu
Notepad Lite File Menu

Double click on the open menu item to wire up the event and open the code editor. Key in the following code, which will display the dialogue box and load the contents of the file selected.

private void evtOpenFile_Click(object sender, EventArgs e)
{
  if (openFileDialog1.ShowDialog() == DialogResult.OK)
  {
    richTextBox1.LoadFile(openFileDialog1.FileName,
      RichTextBoxStreamType.PlainText);
    saveFileDialog1.FileName = openFileDialog1.FileName;
  }
}

The ShowDialog method returns a DialogResult type based on which button was clicked by the user. In this case, we are only interested in performing an action if the user selected a file and pressed OK. The open file dialogue will store the selected filename within the FileName property, which can be passed into the richTextBox LoadFile method. We also need to specify the type of file using a RichTextBoxStreamType type of PlainText. The final line assigns the value of openFileDialog1.FileName to the equivalent property of the saveFileDialog in order for us to simply save the file without prompting for a filename.

When you run the program and open a file, you will notice that we now have a standard Windows open dialogue box that you should be familiar with. You may also notice that we can open any file, including text files, images or even executables. Ideally, we need to be able to limit the types of file that the user can open and we can do that by adding a filter to the OpenDialogBox properties.

Back in the form designer, click on the OpenDialog component and open the properties window and find the Filter property. We need to add in a few file types that we want the user to be able to open. Surprisingly, Visual Studio does not give us a nice property editor for this, so we have to do it by hand. The format for the filter string is Description|Ext|Description|Ext and so on. For our program, we want to be able to open Text Files (*.txt) and Rich Text Files (*.rtf) so our filter string will be

All Supported Files (*.txt; *.rtf)|*.txt;*.rtf|Text Files (*.txt)|*.txt|Rich Text Files (*.rtf)|*.rtf

Now when you run the program you will see that the user can only see files of type Text File or Rich Text File or Both.

Next, we will wire up the Save As menu item in a similar method. Double click on the menu item to create the event handler method. We can copy and paste some of the code from the open method, changing a few of the variable names around. Don't forget to change the Filter property the same as our open dialogue, except we should remove the All Supported Files item.

private void evtSaveAs_Click(object sender, EventArgs e)
{
  if (saveFileDialog1.ShowDialog() == DialogResult.OK)
  {
    richTextBox1.SaveFile(saveFileDialog1.FileName,
      RichTextBoxStreamType.PlainText);
  }
}

You can test this and it will save the current file to disk. The .Net platform will automatically check if a file exists and ask the user to confirm overwriting of the file. You can change this behaviour by altering the OverwritePrompt property of the Save dialogue.

Our final event is the Save method. This is an easy method but relies on our Save As method.

private void evtSave_Click(object sender, EventArgs e)
{
  if (saveFileDialog1.FileName != "")
  {
    richTextBox1.SaveFile(saveFileDialog1.FileName, RichTextBoxStreamType.PlainText);
  }
  else
  { 
    evtSaveAs_Click(sender, e);
  }
}
 

First we check if the FileName is empty. If we have a filename then just call the SaveFile method. If it is empty (i.e. a new document) we need to find out from the user what filename to save the data to so we just call the Save As action which has already been written to get a filename from the user.

There is one final method we need and that is to ask the user if they want to save changes on exit. C# provides an event on the form called FormClosing which is called when the form starts to close. From within this method, you can tell the form not to close, or perform some actions that must be executed at the end of the program (i.e. closing connections or files).

We can use this function to see if the RichTextBox needs to be saved and prompt the user.

private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
  if (richTextBox1.Modified) 
  {
    DialogResult result = MessageBox.Show("Do you wish to Save changes?", "Save Changes", MessageBoxButtons.YesNoCancel);
 
    if (result == DialogResult.Yes)
      evtSave_Click(sender, e);
    else 
      if (result == DialogResult.Cancel) 
        e.Cancel = true;
  }
}

And there we have it, our Notepad Lite application is coming along nicely, and we have learned how to use the save and open common dialogue boxes as well as saving and loading text files.

Menus, Popups and Toolbars in .Net Forms and C#

The two most common types of menu are the standard drop-down menu and the pop-up context menu. These are both found within the Menus & Toolbars tab of the toolbox.

This tutorial is specific to .Net 2.0 and above. In previous versions, a completely different set of components were used which did not have any support for OS visualisations (skins) and they were based on old Win32 technology. The .Net 2.0 versions of these controls are skinnable, draggable, storable and in line with the modern XP/Vista user interface theme.

The Menu Strip and Context Menu Strip

Both controls can be dragged onto a form, and since they are 'non visual' components they will appear in a grey area below the form designer. By clicking on the menuStrip or contextMenuStrip the form designer will show a menu that you can click and type values into, both controls behave in the same manner. The designer will automatically expand to show sub menus.

Visual Studio Menu Designer
Visual Studio Menu Designer

Add a menuStrip component to your form, and create a File menu with two sub items called New and Exit, making the n and x hotkeys.

When you give a menu item a title, you can use the & symbol to define a hotkey, for example, &File will allow the Alt followed by the F key to open the file menu. We will also provide a shortcut key to the new document item by selecting it and changing the ShortcutKeys property of the item. Shortcut keys are usually actioned with the control key, for example (Ctrl+N) for a new document. Finally, we should give the menu item a meaningful name such as evtNewDocument and evtExitProgram. We suggest using the evt prefix as we are dealing with an event (not a C# event, but a user event such as open file, save file, make selection bold etc...), but you could also use mnuNewDocument if you wish.

Toolbars

Toolbars are another method for program navigation. They are commonly a series of buttons along the top of the application, just below the menu. They should be the most common features, or most often used.

Let's create a toolbar on our form by dragging a ToolStrip onto the form. This will allow us to create some buttons and link them to actions. You can create a button on the tool strip by clicking on the down arrow that appears and from there you can select any of the controls on the list. Alternatively, you can right click on the tool strip and select Insert from the menu, and add button from the submenu. This is going to become our New Document button.

You should now give your new button a name, such as btnNewDocument, and give it a meaningful Title and ToolTipText. The title is the text that appears when icons are not shown, and the ToolTipText should be changed to reflect the function that the button performs. The ToolTipText will appear when your mouse is hovered above the button and is usually shown in a yellow pop-up box.

It would be a good idea to give the button a meaningful icon. Visual Studio 2005 gives you a large icon library to choose from, which is located in C:Program FilesMicrosoftVisual Studio 8Common7VS2005ImageLibrary. There is a ZIP archive that you can extract to obtain all the icons; alternatively, you can use any image from the web or hard drive. I used the new document image located in the bitmaps/commands/32bitcolor folder. You may have to change the transparent colour if the image does not look correct. This is a property in the properties and events window. When adding icons to your program, select Project Resource File rather than Local recourse, so that the icon can be reused throughout the project.

Adding a Rich Text Editor

In order to make our sample program a little more functional, we are going to add a rich text editor to the form. A rich text editor will provide an area we can type text into, and at a later date, format it.

Drag a RichTextBox control onto the form and you will see that the control is small, and does not resize when you maximise the window. What we need to do is tell the control to fill the form, a process known as docking. Back in the editor, select the RichTextBox and click on the little arrow in the top right, then select "Dock in parent container". Now try maximising the form or resizing it and notice how the RichTextBox always fills the entire form.

Expand the common format settings window.
Expand the common format settings window.

Adding Some Events

In order to be useful, a menu or toolbar must have an event associated with it. This is done in exactly the same way as adding an event to a button or form: by double-clicking it, or by double-clicking the Click event in the properties window. This will open up the code editor with a new method already declared. All you have to do is type in the code for the action it should perform.

Double click on the exit menu item to launch the code editor and type in the following code to close the program.

private void evtExitProgram_Click(object sender, EventArgs e)
{
  Close();
}

Next, double click on the New menu item and add the following code:

private void evtNewDocument_Click(object sender, EventArgs e)
{
  richTextBox1.Clear();
}

Delegate Events in Action

When we created the New Document menu item, we also created a method called evtNewDocument_Click to handle the click event. We can use that same method on our toolbar button Click event. Click on the toolbar button for New Document that we created and on the properties windows, press the lightning symbol to change to events and find the Click event. On the right-hand side, you will see a drop-down arrow, which expands a list of events that match a click event signature. You should see our evtNewDocument_Click listed and you can select it.

We now have a menu item and a button calling the same method. This not only saves coding time but reduces maintenance overheads and code duplication.

Testing

Run the program and type some text into the RichTextBox, try out the toolbar button and it will clear the contents of the text box. Type some more text into the box and try the new documents menu item. It will also clear the contents of the text box. Now exit the program using File » Exit.

Popup Context Menus

A context menu is typically the "right-click" menu in Windows. These behave in exactly the same way as a regular menu strip, except that they are not visible at design time. To add a context menu simply add a context menu strip from the toolbox to the form and it will be added in the grey area at the bottom of the form designer. Click on it to edit the context menu, and add items for Bold, Italic and Underline. Also, give the items correct names, and optionally apply a font style to the menu items using the Font property in the properties window.

Next, we need to assign the Context Menu Strip to the RichTextBox, so click on the RichTextBox and in the properties window, locate the property called ContextMenuStrip and drop it down and select the new context menu strip. You can test this by running the program and right-clicking on the rich text box. The popup menu will appear each time next to the mouse pointer.

Back in the editor, we will now add some events to the context menu. Double click on each of the items in turn and add in the code below as appropriate.

private void btnFormatBold_Click(object sender, EventArgs e)
{
  richTextBox1.SelectionFont = new Font(richTextBox1.SelectionFont, 
    richTextBox1.SelectionFont.Style ^ FontStyle.Bold);
}
 
private void btnFormatItalic_Click(object sender, EventArgs e)
{
  richTextBox1.SelectionFont = new Font(richTextBox1.SelectionFont, 
    richTextBox1.SelectionFont.Style ^ FontStyle.Italic);
}
 
private void btnFormatUnderline_Click(object sender, EventArgs e)
{
  richTextBox1.SelectionFont = new Font(richTextBox1.SelectionFont, 
    richTextBox1.SelectionFont.Style ^ FontStyle.Underline);
}

Now you can run the program and test the popup context menu, changing the font styles with the popup menus.

Notepad Lite Application
Notepad Lite Application

And there is your first Windows application - Notepad Lite!

Using Multiple Forms in C#

There are two different type of multiform applications, those where another form is used as a dialogue box, i.e. settings or about, and another where there are multiple forms that can all be accessed at the same time, or switched between, such as Microsoft Word. This is known as Multiple Document Interface. This tutorial deals with the former scenario; we will add a new form to our Notepad Lite application and have it manipulate the contents of the text box. We will look at project scope, namespaces and global variables.

To create a new form in Visual Studio or Visual C# Express, click on the Add New Item icon and select Add Windows Form, or you can right click your project on the Solution Explorer, or select File » New » File... and select Windows Form. This will create a new blank form that will form the basis of an Insert Text box. Go ahead and give the new form a name (frmInsertDateTime) and title (Insert Date/Time). Since we do not want this form to be sizeable or maximised/minimised we can disable these features by setting the FormBorderStyle to FixedDialog and MaximizeBox and MinimizeBox to false.

Create a new form in Visual Studio
Create a new form in Visual Studio

We will also add a listBox (lstFormats) and two buttons (btnInsert and btnClose). Set the form's AcceptButton property to btnInsert and the CancelButton property to btnClose. This will handle the return key and escape key actions.

Next, I created a list of date format strings to show in the list box. I declare the list at the top of the class and add items in the form's constructor, and then when the form is loaded I can iterate through the list and add the items to the list box.

public partial class frmInsertDataTime : Form
{
  List<string> dateFormats = new List<string>();
 
  public frmInsertDataTime()
  {
    InitializeComponent();
 
    dateFormats.Add("{0:d}"); // 08/12/2007
    dateFormats.Add("{0:D}"); // 08 December 2007
    dateFormats.Add("{0:t}"); // 15:27
    dateFormats.Add("{0:T}"); // 15:27:40
    dateFormats.Add("{0:f}"); // 08 December 2007 15:27
    dateFormats.Add("{0:F}"); // 08 December 2007 15:27:40
    dateFormats.Add("{0:g}"); // 08/12/2007 15:27
    dateFormats.Add("{0:G}"); // 08/12/2007 15:27:40
    dateFormats.Add("{0:M}"); // 08 December
    dateFormats.Add("{0:r}"); // Sat, 08 Dec 2007 15:27:40 GMT
    dateFormats.Add("{0:s}"); // 2007-12-08T15:27:40
    dateFormats.Add("{0:u}"); // 2007-12-08 15:27:40
    dateFormats.Add("{0:U}"); // 08 December 2007 15:27:40
    dateFormats.Add("{0:Y}"); // December 2007
  }
 
  private void frmInsertDataTime_Load(object sender, EventArgs e)
  {
    lstFormats.Items.Clear();
    foreach (string format in dateFormats)
    {
      lstFormats.Items.Add(String.Format(format, DateTime.Now));
    }
  }

Note that date formatting is dependent on the system regional settings; the example strings here are from my local locale (en-gb).

Back on our main form (frmMain) we need a way to open this new form. To do this, we must first create an instance of frmInsertDateTime, then call its Show method. Add this code into the dateTimeToolStripMenuItem_Click() method.

frmInsertDateTime frmInsertDateTime = new frmInsertDateTime();
frmInsertDateTime.Show();

Next, we need to add a main menu "Insert" with an item titled "Date/Time...". Be sure to name the items correctly and in line with the rest of the menu items created.

The next thing we need to do is assign actions to close the form and to insert the text into the text editor.

On the frmInsertDateTime dialogue designer, create methods for btnClose by double-clicking it and add the following code.

this.Close();

The code for inserting the text is a little more complex, so we will have a look at that in a minute. When you run the program to test it you will be able to click on the menu item and the form will show with the list box filled with the current date and time in different formats. You can select a date time format and close the date time form.

In order to access the richTextBox control on the main form from within our other form, we need to change a few lines of code. Firstly, we need a way to reference the object frmMain rather than the class frmMain, the easiest way is to send the object as a parameter to the constructor and reference that.

In the frmInsertDateTime source we modify the constructor to read as below:

private frmMain theParent;
 
public frmInsertDateTime(frmMain Parent)
{
  InitializeComponent();  
  dateFormats.Add("{0:d}"); // 08/12/2007
...
  dateFormats.Add("{0:Y}"); // December 2007
 
  this.theParent = Parent;
}

Notice the parameter, variable declaration and the assignment. Next, we need to create a public property that we can use to access the private control for frmMain.

We need to modify the frmInsertDateTime.Show() line to pass the frmMain object:

frmInsertDateTime.Show(this)

After the frmMain constructor add this property:

public RichTextBox RichEditor 
{ 
  get { return richTextBox1; } 
  set { richTextBox1 = value; } 
}

This will allow us to read and write to the control from another form. Back to the frmInsertDateTime code and we can now add a line to insert the text:

theParent.RichEditor.SelectedText = lstFormats.Items[lstFormats.SelectedIndex].ToString();

Now when you run the program we have a fully functioning custom dialogue box that is able to access a control on another form

Using Multiple Forms in C# Applications with MDI

Multiple Document Interface (MDI) allows one form to have multiple forms contained within it, like multiple Word documents. It allows a group of windows to be contained and managed within a parent form. Child forms all inherit from a single form class and all contain the same controls.

Visual Studio does all the hard work for you, all you have to do is create a new Windows Forms application and then from the Add a new item dialogue select MDI Parent, give it a name and click OK. Visual Studio will create all the forms, buttons, toolbars and menus that a basic application will need. Right click on Form1 and click on "Exclude From Project". Next, open program.cs and change the line:

Application.Run(new Form1());

to

Application.Run(new MDIParent1());

This will change the start-up form of the project to the new MDI form.

You can run the application now and test the features. You can create as many new forms as you like; some dialogue boxes are linked up while others have placeholders. One thing you should notice is the Windows menu. This lists common items such as Cascade and Tile Vertical as well as listing the child forms already opened. Menu items to control the layout (Tile, Cascade, Minimise, Arrange Icons etc...) all interface with the forms LayoutMdi method, passing in an Enum.

LayoutMdi(MdiLayout.TileHorizontal);

You can iterate through all the open documents:

foreach (Form childForm in MdiChildren)
{
  childForm.Close();
}

A lot of the functionality has been included in the example project supplied, I'll leave it for you to create your own MDI application.

Multiple Document Interface (MDI)
Multiple Document Interface (MDI)

Creating Controls for Windows Forms and C#

Just like ASP.Net, Windows forms allow the creation of custom controls to extend or enhance existing controls or to create brand new functionality.

Like ASP.Net, there are different types of custom control in WinForms, some with a designer to add controls (User Control or Composite Control) and others that exist purely in C# (Custom Control) and allow greater freedom in drawing and graphics. You can also create a normal C# class and create inherited controls.

There are many reasons why you may want to extend an existing control. Maybe you need to change the default properties, override the Paint method, add validation events by default. In this tutorial, I will show you how to extend some of the basic controls and extend their functionality.

Extending a Button control

The simplest control to look at is the button control. I'm going to create a new control inherited from a button and I'm going to change a few of the default properties. The reason for doing this is so that all buttons in the application can have the same class and set of properties. If a change needs to be made, a quick modification to the class changes all the buttons in the project. By contrast, if you added the base button control and changed all the properties manually, you would have to go through all the forms in the application and update each button manually.

I used this technique while developing a touchscreen interface. I needed each button to be larger and have a different colour scheme but didn't want to apply the properties to all of the buttons individually. All you need to do is add this control to the form instead of the base button.

To create an inherited control, simply create a new C# class file with a meaningful name and set the class to inherit from the base class, as shown below.

using System;
using System.Windows.Forms;
using System.Drawing;
 
/// <summary>
/// Summary description for TouchscreenButton
/// </summary>
public class TouchscreenButton : Button
{
    public TouchscreenButton()
    {
        this.Width = 100;
        this.Height = 75;
        this.FlatStyle = FlatStyle.Flat;
        this.Cursor = Cursors.Hand;
        this.ForeColor = Color.Black;
        this.BackColor = Color.White;
        this.FlatAppearance.BorderSize = 2;
        this.FlatAppearance.BorderColor = Color.Navy;
    }
}
 

When you add this class and build the project, you will see a new section in the toolbox with the name of your project, and within that an entry for a TouchscreenButton. We'll have a look at the toolbox and options later in this tutorial.

Each time you add a TouchscreenButton to the form, it will have the same default properties as specified above. This is incredibly handy if you are using multiple controls on multiple forms.

Creating Custom Controls for Windows Forms
Creating Custom Controls for Windows Forms

You can also instantiate controls and add them to a form with code and you need not set all the properties.

TouchscreenButton tbtnMyButton = new TouchscreenButton();
placeHolder1.Controls.Add(tbtnMyButton);

You can use this method to override or extend methods, add additional properties or change the behaviour of an existing control.

User Controls

User controls allow you to use the designer to create a composite control (a control made up of other controls). For example, you can add a textbox and a button to the same control and add this new control to a form to save time and effort. This new control handles the logic rather than the form so it aids in scalability and reusability.

To create a new user control, add a new item to the project and select User Control.

I'm going to create a control that will handle file browsing, and simulate a process. This will have a textbox for the filename, a button to select a file, a button to process the file and a progress bar for a simulated process. Using the designer and creating the code behind is just like designing a form so I won't go through this process. You can download the code at the end of this article.

Creating Controls for Windows Forms
Creating Controls for Windows Forms

When using this control in an application, all you need to do is to add the control from the toolbox. All the boxes, buttons and logic will be handled already and your application does not need to do anything. If you choose to add some events to the user control (validate filename, or delegate the process method) your client application can simply subscribe to the events as it would any other control.

Creating Controls for Windows Forms
Creating Controls for Windows Forms

Custom Controls

The final control type is the custom control. This does not have a designer but does let you draw your own graphics. In this part of the tutorial, I am going to create a Smiley control that displays a smiley face.

You can create a custom control by adding a new file to your project and selecting Custom Control.

The OnPaint() method is used to draw shapes using the PaintEventArgs.Graphics property. In a more realistic environment you would use this to draw graphs or charts, but for this example, I'll draw a smiley.

The code behind looks like this:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
 
namespace WindowsApplication1
{
    public partial class Smiley : Control
    {
        public Smiley()
        {
            InitializeComponent();
        }
 
        protected override void OnPaint(PaintEventArgs pe)
        {
            // Draw a basic smiley face
            pe.Graphics.FillEllipse(Brushes.Yellow, 0,0,this.Width-1, this.Height-1); // Face
            pe.Graphics.FillEllipse(Brushes.Black, (this.Width / 4), (this.Height / 4), (this.Width / 6), (this.Height / 6)); // Left Eye
            pe.Graphics.FillEllipse(Brushes.Black, this.Width - (this.Width / 3)-10, (this.Height / 4), (this.Width / 6), (this.Height / 6)); // Right Eye
            pe.Graphics.DrawArc(Pens.Black, (this.Width / 4), (this.Height / 2), (this.Width / 2), (this.Height / 4), 0, 180); // Mouth
 
            // Calling the base class OnPaint
            base.OnPaint(pe);
        }
    }
}
 

It's only basic, but it shows how to draw using the graphics and what's more it will scale when the control is resized. This is what it looks like on the form:

Creating Controls for Windows Forms
Creating Controls for Windows Forms

That's just about it for the controls. We've seen how to create inherited controls, user controls and custom controls.

Adding Properties

You can add a property to the property window for your control simply by creating a public property.

private string _smileyName;
public string SmileyName
{
    get { return _smileyName; }
    set { _smileyName = value; }
}

You can use this method for any of the basic data types such as int, string, bool, decimal and so on. You can also use this to create an advanced data type such as a enum as shown in the example below.

Control Properties
Control Properties
public enum SampleColours
{
    Red,
    Green,
    Blue,
    Yellow
}
 
private SampleColours _smileyColor;
public SampleColours SmileyColor
{
    get { return _smileyColor; }
    set { _smileyColor = value; }
}
 

This will be shown as a drop down list containing the items in the enum.

Control Properties
Control Properties

Last updated on: Thursday 11th October 2018

 

Comments

Have a question or suggestion? Please leave a comment to start the discussion.

Matt

Matt

Short, concise, beautiful.

Reply to Matt

 

Leave a Reply

Please keep in mind that all comments are moderated according to our privacy policy, and all links are nofollow. Do NOT use keywords in the name field. Let's have a personal and meaningful conversation.

Your email address will not be published.