How are Windows Forms Controls Created and Rendered Onto a Form?

In order to answer this question, I will use a project that I created in a previous demo. This demo is available here https://win-forms.com/2020/08/16/shapes-objects-and-lists-with-windows-forms/. You may clone the repository or download the code from here https://github.com/dwarwick/Shapes.

This post will cover how Windows Forms, or winforms for short, handles drawing controls on the forms. Examples of controls are text boxes, labels, list boxes, combo boxes, etc.

When you create a winforms project, a single windows form is created. The name of the form is Form1 by default, but you can, and should, rename it. You can also add as many additional forms to your project as you need.

Form Files

Each form consists of 3 files by default. For the purposes of this discussion, we will assume the name of the form is MainForm.

MainForm.cs is a file that normally contains all of the logic code behind the form. This file contains code that interacts with the controls on the form and the algorithms that make the program do what it is supposed to do.

MainForm.Designer.cs is a file that actually creates the controls, sets the initial property values of the controls, and renders the controls onto the form. This is what we will be diving into for this post.

MainForm.resx contains resources that are used by the form. We will not be discussing this today.

Identifying the 3 Files that Are a Form

We can browse to our solution folder to view these files on our hard drive as well. With MainForm.cs selected, you can view the path to the file in the properties window.

Finding File Location Using Properties Window

Lets open our File Explorer and navigate to the folder to view the form files.

File Explorer View of Project Files

In the File Explorer view, you can see 3 distinct files named MainForm.cs, MainForm.Designer.cs, and MainForm.resx. Close the File Explorer window and go back to Visual Studio.

Design View of Form

In the Solution Explorer, double click MainForm.cs. You will see the form open in Design View.

Form Open in Design View

This form was created by dragging and dropping each control onto the form and setting properties on each control using the properties window. See the Shapes Demo for more details on this.

Designer File Code

Open the MainForm.Designer.cs file to view the code that is used to create all of these controls and set the property values for each control.

Designer File Control Variables

In the image above, you can see that there are several variables that are declared. Each variable is named for one of the controls that are being used on our form. There are variables of type TextBox, Button, and Label. Each variable has of course been declared and given a Name such as txtBox_X. Each time a new control is dragged onto the form, Visual Studio creates a new variable in the designer file for you.

Now expand the plus sign next to the words Windows Form Designer generated code if you have not already expanded it.

You may see other plus signs that need to be expanded to view the full code in this file.

Plus Sign

The code in the image above simply declares a variable that represents a control. It does not actually create the control or define any properties.

InitializeComponent Method

Notice that there is a method named InitalizeComponent. This method is responsible for initializing all new controls and setting the properties on those controls.

As I stated before, when you drop a control on the form, a new variable is created for the control. At the same time, Visual Studio adds a new line of code to create a new instance of the control and sets some default property values for the control such as Name and TabIndex. And depending on where you drop the control and what size you make it, it sets the Location and Size properties as well.

Scroll down to the bottom of the InitializeComponent method.

Form Properties

Here you can see that our textboxes, labels, and button are actually added to the Controls Collection of the form. The controls are not actually associated with the form until they are part of the form Controls Collection. Next the Layout is performed and the form will be loaded with the controls positioned according to their assigned properties. This is the end of the InitializeComponent method.

The InitializeComponent method is called from the constructor of the MainForm class. Right click MainForm.cs and select View Code.

Initialize Component Method Called from Form Constructor

When we start debugging a form, the constructor runs before any other code in the MainForm class. The constructor runs the InitializeComponent method to load and position the controls onto the form.

Any changes that are made to a control on the form in design view are automatically updated in the designer file. If you change the color of a text box, or resize it, or set it to disabled, or make any other changes to it, those properties are updated automatically in the designer file.

Events

Events are also associated with their methods in the designer file. Have a look at the button properties in the designer file.

Button Click Event in Designer File

Here you can see that btnDraw Click event is associated with a method named btnDraw_Click. This line is added when you either double click a button in the form design view, or double click the click row for the button in the property window, or when you use the property window to browse to a button event method that has already been created in MainForm.cs.

If you enjoyed this post, please Like it so that you will be notified of new posts as I create them. I also have several other posts about Windows Forms available on my blog home page at https://win-forms.com.

If you have questions, comments, or suggestions, please leave a comment below.

Shapes, Objects, Classes, and Lists with Windows Forms

What are we creating?

This video shows an example of what we will be creating

The main goal of this topic is to learn how to create and use classes and objects using windows forms. Along the way, you will learn about classes and objects, variables, scope, Lists, parameters, constructors, and events. This topic is going to be written to the beginner level, but experienced programmers may also get something out of it.

Full Video of this Tutorial

Full Video of Tutorial

Set Up Your Environment

Let’s start with ensuring that you have Visual Studio installed and configured for Windows Forms development. If you do not, head over to my other post at https://win-forms.com/2020/07/25/create-a-hello-world-winforms-application/. Once Visual Studio is installed, come back here.

You may choose to download the entire project / solution from my Github repository here https://github.com/dwarwick/Shapes. This may allow you to follow along better as I explain everything. If you choose to type everything yourself, let’s get started.

Create a new Project

Create a new Windows Forms project called Shapes in Visual Studio.

Creating a New Project
Select Windows Forms App (.Net Framework)
Name the Project and Solution Shapes

After you click Create here, your blank project template will be created and shown to you.

Rename Form1

Solution Explorer

By default, Visual Studio created a Form for you and named it as Form1. We want to always name our forms according to how they will be used. Since this is the only form we will have in this project, let’s name it MainForm as I have done in the image above.

Right click Form1 and select Rename. Rename it to MainForm and then press the Enter key.

By the way, notice in the image above that my files have little blue padlocks next to them. Do not worry if you do not see those in your Solution Explorer. The reason I have them is because my solution is using Source Control. This is completely optional.

Let’s Build our Form

Double Click MainForm.cs in the Solution Explorer to open the form in Design View. Another way of opening it is to Right Click the form and select View Designer from the Right Click menu.

Completed Form

The image above shows what the completed form will look like. There are 5 text boxes for accepting user input, 5 labels for describing the purpose of the text boxes, and 1 button that when clicked, will tell our application to draw a box. The idea is that the application user will enter length, width, and height values for a box, and they will enter the X and Y origin values to define the location of the box on the form. When the user clicks the Draw button, a box will be drawn on the form at the origin location.

Open the Toolbox in Visual Studio. It should be on the upper left edge of the Visual Studio window by default.

Default Location of Toolbox in Visual Studio.

This is a screen capture from my Hello World demo, but it does show where the Toolbox is located. If you do not see it, go to the View menu and select Toolbox.

With the Toolbox open, drag 5 Textbox controls onto the form and arrange them as I showed in the Completed Form image above. Next, drag 5 labels and arrange them as I showed in the Completed Form image. Finally, drag a button onto the form and arrange it as I showed in the Completed Form image. Now we will set the text property on these labels.

Label Controls

Select the label that will display the text Length. You select a control by clicking it one time with the left mouse button. It should be above the top text box and may currently display label1 or label2 or something like that. When the control is selected, you will see a faint gray border around it and the properties window will display the name and type of control that is selected at the top of the properties window. You should see something like this.

What a Label Looks Like when Selected

Notice the faint gray border around Length and that the name of the label, label1, is displayed at the top of the properties window and the type of control, System.Windows.Forms.Label is also displayed.

Now look down the list of properties and find the Text property. Set the Text property to Length.

Setting the Text Property

Note that your list may look different than mine if you have your properties list set to Alphabetical . Mine is set to Categorized . Also ensure that you are looking at Properties and not Events . Look at the top of the image above at the 2 blue outlined squares and ensure that you have the same squares selected.

Now set the Text property for the 4 other labels as I did in the Completed Form image above. You should still need to set the Text property for Width, Height, Box Origin X, and Box Origin Y labels.

Textbox Controls

We will be referencing the textbox controls in code, so we need to ensure that we give them a meaningful name. By convention, you should name a control to indicate the type of control as well as the purpose of the control. For example, the name of the Length textbox will be txtLength. This indicates that it is a textbox that will hold a length value. Select each textbox in the same way that you selected the labels. Name the 5 textboxes using the Name property for each textbox as follows:

LengthtxtLength
WidthtxtWidth
HeighttxtHeight
Box Origin XtxtBox_X
Box Origin YtxtBox_Y
Textbox Name Properties
Name Property for txtLength Textbox

Draw Button

Select the button that is on the form. We will be referencing this button in code, so once again, we need to give it a Name that will represent the type of control it is and its purpose. For this button, we will name it btnDraw. With the button selected, set the Name property to btnDraw. Set the Text property to Draw.

Form Header Text

I almost forgot about one very important property. The top left border of your form may say Form1 if you haven’t already changed it. Select the form itself by clicking anywhere on the form and not on one of your controls. When the form is selected, you will see sizing handles around the form and at the top of the properties window, you will see System.Windows.Forms.Form.

Find the Text property for the form and set it to Shapes. Now instead of seeing Form1 at the top of the form, you should see Shapes.

Setting the Form Text Property

Let’s Code the App!

Ok, now it is time to start coding the application. With the form still selected, press F7, or right click MainForm in the solution explorer and select View Code.

namespace Shapes
{
    public partial class MainForm : Form
    {
        public MainForm() // constructor
        { //add textboxes, labels, and the button to the form
            InitializeComponent(); 
        }
    }
}

The code that you see here is the “starter code” for the app. When the MainForm runs, the constructor runs the InitalizeComponent method. This method loads all of the controls onto the form according to the way we configured them.

If you run the app now, you would see the form load and you would see the textboxes, labels, and the button. You would be able to add text to the textboxes. You would also be able to click the button, but you wouldn’t see anything happen because we haven’t told the application what to do when we click the button. Go ahead and click the green Start arrow at the top of Visual Studio to run the application.

Create the Box Class

The Box class will tell the application what a Box is. We have to tell it that that it has a length, a width, a height, that it will be drawn in blue, and where to draw it. We have to tell it that it will be given the values for length, height, and width, and the Origin X and Y values.

Time for Me to be Honest With You

Now I have to be honest with you. I do not usually create graphics in Windows Forms applications. I chose to use Graphics for the Box demo because I figured it would be better to use visuals to demonstrate classes and objects. I had to learn how to draw a Box on a Windows Form in order to prepare for this demo.

One thing you will learn as you become a seasoned software developer and begin to work with other developers is that there are no developers that know everything about programming. I would say that almost all programmers learn something new about programming almost every day.

The really good programmers know where and how to find the information they need to work on their development projects. In my experience, probably the best resources that you will ever discover are Google and Stack Overflow.

I entered the following search term into Google, “windows forms draw a cube”. You should try it. I found the following website that gave me most of the code for the Box class https://www.daniweb.com/programming/software-development/threads/369044/drawing-cubes-in-c-using-system-drawing.

I did add my own code and made some changes to it for my own needs, but what I did is quite common for both new and seasoned programmers.

The Box Class Code

class Box
{
    private int m_iHeight; //Class Member Variables
    private int m_iWidth;
    private int m_iLength;
    private int m_iOriginX;
    private int m_iOriginY;

    public Box(int iHeight, int iWidth, int iLength, int iOriginX, int iOriginY)
    {
        m_iHeight = iHeight; // Constructor
        m_iWidth = iWidth;
        m_iLength = iLength;
        m_iOriginX = iOriginX;
        m_iOriginY = iOriginY;
    }

    public void Draw(Graphics graphics) //Method
    {
        /*
            * Obtained from 
            * https://www.daniweb.com/programming/software-development/threads/369044/drawing-cubes-in-c-using-system-drawing
            */
        Point origin = new Point(m_iOriginX, m_iOriginY); //Location of Box
        Pen pencil = new Pen(Color.Blue, 1f); //Blue pencil
        Rectangle R = new Rectangle(origin.X, origin.Y, m_iWidth, m_iHeight);
        graphics.DrawRectangle(pencil, R); // Draw Rectangle

        graphics.DrawLine(pencil,
                            origin.X, origin.Y,
                            origin.X + m_iLength,
                            origin.Y - m_iLength);// Top left edge

        graphics.DrawLine(pencil,
                            origin.X + m_iLength,
                            origin.Y - m_iLength,
                            origin.X + m_iWidth + m_iLength, origin.Y - m_iLength); //Top back width

        graphics.DrawLine(pencil,
                            origin.X + m_iWidth + m_iLength,
                            origin.Y - m_iLength,
                            origin.X + m_iWidth,
                            origin.Y); //Top Right Edge

        graphics.DrawLine(pencil,
                            origin.X + m_iWidth + m_iLength,
                            origin.Y - m_iLength,
                            origin.X + m_iWidth + m_iLength,
                            origin.Y - m_iLength + m_iHeight); //Back Right Edge

        graphics.DrawLine(pencil,
                            origin.X + m_iWidth + m_iLength,
                            origin.Y - m_iLength + m_iHeight,
                            origin.X + m_iWidth,
                            origin.Y + m_iHeight); //Bottom Right Edge
    }
}

The Box class is nothing on its own. In order for it to mean something in the application, something in the MainForm of our app has to create a new Box Object. Objects are created from classes using the new keyword. We will get to that later. For now, lets discuss what is going on inside the Box Class.

When a new Box object is created, the Box constructor is called. See below:

    private int m_iHeight; //Class Member Variables
    private int m_iWidth;
    private int m_iLength;
    private int m_iOriginX;
    private int m_iOriginY;

    public Box(int iHeight, int iWidth, int iLength, int iOriginX, int iOriginY)
    {// Constructor
        m_iHeight = iHeight; 
        m_iWidth = iWidth;
        m_iLength = iLength;
        m_iOriginX = iOriginX;
        m_iOriginY = iOriginY;
    }

The constructor “constructs” the box by accepting the values for height, width, length, originX, and originY. Notice these variables inside the parenthesis of the constructor. Those are called parameters. Those parameters can only be used inside the constructor curly braces.

The class Member Variables can be used throughout the entire class. They are accessible inside the constructor and inside the Draw method. Notice that I named the class member variables starting with the letter m so that I can immediately tell that it is a class member variable. This is not so important inside a small class, but in a class with thousands of lines of code, it is easy to lose track of local variables (variables declared inside of methods) vs class member variables.

The class member variables are declared at the class level but get a default value of 0. They are assigned the values of the constructor parameters inside the constructor. Imagine that we were creating a box with the following values:

Height50
Width100
Length25
OriginX100
OriginY75

Paying attention to the order of parameters in the constructor, we would actually create a new Box like this:

Box boxObject = new Box(50,100,25,100,75);

The numbers in the parenthesis are passed to the constructor parameters. The parameters will now have those values. Then the member variables will be assigned to their respective parameter values. m_iHeight will now have a value of 50. m_iWidth will have a value of 100, and so on. Hopefully this is clear. If not, leave a comment below.

The Draw Method

public void Draw(Graphics graphics) //Method
{
    /*
        * Obtained from 
        * https://www.daniweb.com/programming/software-development/threads/369044/drawing-cubes-in-c-using-system-drawing
        */
    Point origin = new Point(m_iOriginX, m_iOriginY); //Location of Box
    Pen pencil = new Pen(Color.Blue, 1f); //Blue pencil
    Rectangle R = new Rectangle(origin.X, origin.Y, m_iWidth, m_iHeight);
    graphics.DrawRectangle(pencil, R); // Draw Rectangle

    graphics.DrawLine(pencil,
                        origin.X, origin.Y,
                        origin.X + m_iLength,
                        origin.Y - m_iLength);// Top left edge

    graphics.DrawLine(pencil,
                        origin.X + m_iLength,
                        origin.Y - m_iLength,
                        origin.X + m_iWidth + m_iLength, origin.Y - m_iLength); //Top back width

    graphics.DrawLine(pencil,
                        origin.X + m_iWidth + m_iLength,
                        origin.Y - m_iLength,
                        origin.X + m_iWidth,
                        origin.Y); //Top Right Edge

    graphics.DrawLine(pencil,
                        origin.X + m_iWidth + m_iLength,
                        origin.Y - m_iLength,
                        origin.X + m_iWidth + m_iLength,
                        origin.Y - m_iLength + m_iHeight); //Back Right Edge

    graphics.DrawLine(pencil,
                        origin.X + m_iWidth + m_iLength,
                        origin.Y - m_iLength + m_iHeight,
                        origin.X + m_iWidth,
                        origin.Y + m_iHeight); //Bottom Right Edge
}

The Draw method accepts of parameter of type Graphics that we name graphics. This parameter is passed from MainForm and represents the drawing surface of MainForm. This is the surface where all of the controls are drawn. So when we draw the Box on graphics, it will be displayed on the drawing surface of MainForm.

It’s kind of like you handing a piece of paper to someone and telling them, “please draw a box on this piece of paper”. When they draw the box, it is still your piece of paper. Welcome to object oriented programming. The paper, or drawing surface, is the object. Looking over the code for the Draw method, whenever you see the variable graphics, think to yourself, “this represents the drawing surface of MainForm”.

Using the Point class, we define x and y coordinates for the Box object. The name of the origin will be simply, origin. It contains the properties X and Y that are used to specify the coordinates of the rectangle, as well as the starting and ending points of each additional line.

We define a Pen that we decided to call pencil for some reason. It is a blue Pen. We also use it to draw the rectangle and each line.

Next we begin to draw on graphics, which as we discussed earlier, is our drawing surface. First we draw the rectangle and then all of the lines. Remember, the drawing surface belongs to the MainForm. So whatever we draw here will show up on the MainForm.

Final Code After Completing Box Class

namespace Shapes
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        } //Closes MainForm constructor
    } // Closes MainForm class

    class Box
    {
        private int m_iHeight; //Class Member Variables
        private int m_iWidth;
        private int m_iLength;
        private int m_iOriginX;
        private int m_iOriginY;

        public Box(int iHeight, int iWidth, int iLength, int iOriginX, int iOriginY)
        {
            m_iHeight = iHeight; // Constructor
            m_iWidth = iWidth;
            m_iLength = iLength;
            m_iOriginX = iOriginX;
            m_iOriginY = iOriginY;
        } //Closes Box constructor

        public void Draw(Graphics graphics) //Method
        {
            /*
                * Obtained from 
                * https://www.daniweb.com/programming/software-development/threads/369044/drawing-cubes-in-c-using-system-drawing
                */
            Point origin = new Point(m_iOriginX, m_iOriginY); //Location of Box
            Pen pencil = new Pen(Color.Blue, 1f); //Blue pencil
            Rectangle R = new Rectangle(origin.X, origin.Y, m_iWidth, m_iHeight);
            graphics.DrawRectangle(pencil, R); // Draw Rectangle

            graphics.DrawLine(pencil,
                                origin.X, origin.Y,
                                origin.X + m_iLength,
                                origin.Y - m_iLength);// Top left edge

            graphics.DrawLine(pencil,
                                origin.X + m_iLength,
                                origin.Y - m_iLength,
                                origin.X + m_iWidth + m_iLength, origin.Y - m_iLength); //Top back width

            graphics.DrawLine(pencil,
                                origin.X + m_iWidth + m_iLength,
                                origin.Y - m_iLength,
                                origin.X + m_iWidth,
                                origin.Y); //Top Right Edge

            graphics.DrawLine(pencil,
                                origin.X + m_iWidth + m_iLength,
                                origin.Y - m_iLength,
                                origin.X + m_iWidth + m_iLength,
                                origin.Y - m_iLength + m_iHeight); //Back Right Edge

            graphics.DrawLine(pencil,
                                origin.X + m_iWidth + m_iLength,
                                origin.Y - m_iLength + m_iHeight,
                                origin.X + m_iWidth,
                                origin.Y + m_iHeight); //Bottom Right Edge
        } //Closes Draw Method
    } //Closes Box class
} // Closes Shapes Namespace

Now we will begin to work on the MainForm class code.

We Need a List

One of the things that we want to achieve is to be able to create and draw multiple boxes on our form. So for that, we need something to hold multiple Box objects. If we didn’t use something to hold multiple Box objects and instead we recreated the same object over and over again, we would ever only see 1 Box on the form.

Lucky for us, there is a simple solution to this problem. C# provides us with something called a List. A List is a list of things. It can be a list of any type of class. It can be a list of integers or strings, or virtually anything you can think of. In our case, we will make it hold a list of Boxes.

I use Lists in pretty much all of my code. They are easy to search through and are very fast. The official documentation is here, but I will show you how easy they are to work with in this tutorial.

First of all, we need to be able to access the list in several places in our code. We have a decision to make, do we want to pass the list around from method to method, or do we want to make it available to the entire class. There is no right or wrong answer. It depends on your project and it is up to you to decide how to do it. In my case, I decided to declare the list at the class level so that it is available to the entire class. We will declare it just inside the class right above the constructor.

partial class MainForm : Form
    {//Beginning of class

        // m_myBoxes is available to the entire MainForm class
        private List<Box> m_myBoxes;

        public MainForm()
        {
            //Default Constructor
            InitializeComponent();
        }
    } // Closes MainForm class

We have declared a List of type Box called m_myBoxes. The m_ helps us to quickly recognize that it is a member of the class, which means it has class scope and can be used anywhere in the class. At this point, m_myBoxes is null, which means it has never been assigned a value. It has only been declared.

We want the list to be initialized when the form loads. Once it is initialized it will no longer be null and will initially be a list of 0 objects (boxes). But since the list is initialized, we will be able to add boxes to it.

There is an event handler for the Form Load event. This is the perfect place to put code that you want to execute when the form has loaded. In order to create the event handler, go select the form in design view by single clicking the form while ensuring that you have not clicked a control such as a text-box or button. See the image below.

Ensuring the Form is Selected.

After you select the form, we want to select the Events button at the top of the properties window.

Location of Form Load Event

In the image above, there is nothing in the Method cell to the right of the word Load. Therefor, no method will run when the form loads. We want a method to run when the form loads, so we need to create a Form Load Event Handler. We can do that by simply double-clicking anywhere on the Load row of the properties window. When we do that, Visual Studio will create an empty load method for us and will create a Load Event handler.

partial class MainForm : Form
    {//Beginning of class

        // m_myBoxes is available to the entire MainForm class
        private List<Box> m_myBoxes;

        public MainForm()
        {
            //Default Constructor
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            //all code contained in this method 
            //will run when the form has loaded.
        }
    } // Closes MainForm class

You can see a new blank method called private void MainForm_Load was created for us. I placed a comment inside the method that indicates that all code inside that method will run when the form has loaded.

If you switch back over to the MainForm Design view, you will see that this method is now listed in the properties window under the MainForm events Load row.

Showing Load Method in Properties Window

Note that if you simply copy and paste the Load method code into the code window instead of double clicking the Load row of the property window, the Load method will not execute. Double clicking the Load row of the property window actually performs some magic in the background by associating the Load Event for this form with this particular method.

Switch back over to the code tab so that we can add code to the Form Load event method.

Click this Tab to Get Back to Code Window

The code that we will add to this method is pretty simple. The only thing we need to do when the form loads is to create a new List. When we create the list, we need to specify what we want the list to hold. In our case, we want it to hold Box objects.

 private void MainForm_Load(object sender, EventArgs e)
{
    //all code contained in this method 
    //will run when the form has loaded.
    m_myBoxes = new List<Box>();

    /* m_myBoxes is now an empty
     * usable list that can be used
     * everywhere in the class.
     * 
     * If it were declared in this
     * method, it could only be 
     * used in this method.
     * 
     * For example, if we did this:
     * List<Box> m_myBoxes; 
     * m_myBoxes = new List<Box>();
     * or 
     * List<Box> m_myBoxes = new List<Box>();
     * 
     * then this variable could only be used inside
     * this method
     */
}

Notice that we are only initializing the m_myBoxes variable. We are not declaring it. It was declared at the class level. This makes a difference. If we had declared it inside the Form Load method, it could only be used inside the Form Load method. See the multi-line comments in the code above.

Lets inspect our m_myBoxes variable in Debug mode. Add a breakpoint on the line next to the initialization of m_myBoxes. Left click one time in the code margin directly to the left of m_myBoxes to set the breakpoint. You will see a red circle when the breakpoint is set as shown in the image.

Showing Breakpoint on m_myBoxes

When the breakpoint is set, click the green arrow Start button at the top of the Visual Studio to run the program in Debug mode, or press F5. Ensure that Debug is set and not Release before you start Debugging.

Start Debugging

It may take several seconds for Visual Studio to compile our program, but eventually, code execution will stop at our breakpoint.

Code Execution Stopped at Breakpoint

The image above shows what you should see when code execution has stopped at the breakpoint. With the execution stopped like this, we can inspect the m_myBoxes variable. Hover the mouse over the m_myBoxes variable.

Inspecting the m_myBoxes Variable

You can see that m_myBoxes currently has a value of null. This is because this line of code has not executed yet. m_myBoxes has not yet been initialized. If you hover your mouse over the m_myBoxes variable at the class level where it was declared, you will see the same value of null.

Press F10 on your keyboard one time to allow this line of code to be executed. The yellow arrow will move to the closing brace of the Load method. Now inspect m_myBoxes. The variable has now been initialized.

Inspecting m_myBoxes after it Has Been Initialized

You can see in the image above that code execution has moved past the m_myBoxes initializer to the end of the method. Once m_myBoxes has been initialized, it is no longer null and has a value. It indicates that there are 0 Box objects in the list. Try inspecting the m_myBoxes variable where m_myBoxes was declared at the class level. It will show the same results, which proves that it is the same variable.

At this point, you can either Continue and let the program finish loading and then close the form to end the Debug session, or press the Stop button at the top of the Visual Studio window. Left click the breakpoint (red circle) to clear it so that the next time we start debugging, it doesn’t stop there.

Let’s Create Some Box Class Objects

We will start by creating a method called CreateNewBox. This method will create a new Box and add the Box object to our list of boxes. First, let me post the code for this method and then we will go through it line by line.

private void CreateNewBox()
{
    /*
     * Note that in newer versions of
     * Visual Studio, these variables
     * can be "in-lined" below, but
     * I am declaring them this way
     * for backwards compatibility.
     */

    int iLength;
    int iHeight;
    int iWidth;
    int iOriginX;
    int iOriginY;

    if (int.TryParse(txtLength.Text, out iLength)
        && int.TryParse(txtWidth.Text, out iWidth)
        && int.TryParse(txtHeight.Text, out iHeight)
        && int.TryParse(txtBox_X.Text, out iOriginX)
        && int.TryParse(txtBox_Y.Text, out iOriginY)
        )
    {
        Box box = new Box(iHeight, iWidth, iLength, iOriginX, iOriginY);
        m_myBoxes.Add(box);
    }
}

First, let me start by explaining these int (integer) variables. These variables are declared inside this method because we assign the type (int) to them. We are not assigning a value to them. Integer variables that are not assigned a value when they are declared have a default value of 0. Since the variables are declared inside this method, they are considered to be local variables and can only used inside this method. However, as you see later on in the method, their value can be passed to the Box class Constructor. This is called passing By Value and is the default way of passing variables in C#.

The whole reason that we are creating these integer variables is because we want to validate that the user input valid values in the textboxes prior to creating a Box. All of the Box class Constructor parameters are integers. We need to ensure that the user typed integer values into all of the text boxes.

We will accomplish this validation by using a method called TryParse which is a method of the int primitive type. TryParse takes a string value as an argument and tries to convert it to the primitive type. In our case, it tries to convert it to an integer. The string argument will come from the value that the user types into a textbox. If the conversion is successful, the out variable will be equal to the converted integer value and the TryParse method will evaluate to true.

Lets look at the iLength variable and the txtLength textbox. Let’s assume the user typed the letter R in txtLength. The Text property of txtLength would be equal to the letter R. So the line of code int.TryParse(txtLength.Text, out iLength) would try to convert the letter R to an integer, which would of course fail. The TryParse method would return false which would make the if statement return false and none of the code inside the if block would execute. One false in all of the if &&’s would make the if false.

If the user enters valid integers in all of the textboxes, then the code inside the if block will execute. First, a new Box named box is created using the integer values that the user enters into the textboxes. Next the box is added to the list of boxes named m_myBoxes.

When the new box is created, it passes those integer values to the Box class Constructor. The order of the parameters inside the parenthesis must match the order of the parameters of the Box class Constructor. See below.

// creating a new instance of the Box class 
// from the MainForm class
Box box = new Box(iHeight, iWidth, iLength, iOriginX, iOriginY);

// Accepting the passed parameter values in 
// the Box Class Constructor
public Box(int iHeight, int iWidth, int iLength, int iOriginX, int iOriginY)

The fact that the variables happen to have the same name in the code above is irrelevant. The important thing is that the order of the parameters are the same.

Let’s add a new Click Event handler method for the button and then we will step through this code so that you can clearly see what is going on.

Enable the Draw Button

We need to create a Click Event handler for the Draw button so that it does something when we click it. Select the MainForm Design tab to view the form in design view.

Form Design View Tab

Select the Draw button on the form by single clicking it. You will see the name of the button, btnDraw, at the top of the properties window when it is selected. Select the Events Lightning Bolt button at the top of the properties window if it is not already selected.

btnDraw Selected Looking at Events

As circled in the image above, we need to create a Click event method for the btnDraw button, but there are no methods currently associated with this button. Double click anywhere on the Click row of the property grid to create the Click event method.

private void btnDraw_Click(object sender, EventArgs e)
{
    // all code in this method will execute 
    // when the Draw button is clicked
}

We now have an empty btnDraw click method. I added the comment to the empty click event method to indicate that all code inside that method will execute when btnDraw is clicked.

Note that if you simply copy and paste the btnDraw click event method code into the code window, the btnDraw click event method will not run when the button is clicked. This is because when you double click the Click row of the property window, some magic happens in the background to actually associate the click event for this button with this method.

When we click the Draw Button, we want to create a new box. So let’s call the CreateNewBox method that we created earlier. Type CreateNewBox(); into the click event method.

private void btnDraw_Click(object sender, EventArgs e)
{
    // all code in this method will execute 
    // when the Draw button is clicked

    CreateNewBox();
}

Now that we have done this, when we click the draw button, CreateNewBox will be called which will create a new box and add the box to our list of boxes, m_myBoxes. Lets try it. But before we do, set a breakpoint on the opening brace of the btnDraw click event method. We want to step into the CreateNewBox method so that we can see what is happening in this method. Single Click in the left margin as I have done in the image below to set the breakpoint. The red circle is the breakpoint.

Breakpoint in Draw Button Click Event Method

Ensure that you are in Debug mode instead of Release mode and click the green Start arrow or press F5 to start debugging the application.

Starting Application in Debug mode

After a few seconds, or a little longer depending on your computer, the application should launch and show your form. Hopefully you remembered to clear your breakpoint that we set earlier in this tutorial. If not, click the breakpoint once to clear the breakpoint on the m_myBoxes variable in the Form Load event method.

Try entering some integer values in all of the textboxes. It doesn’t matter what values you enter as long as they are integers.

Form Filled Out

Now that we have integer values in our textboxes, click the Draw button. You should see the code window pop up and code execution will stop at the beginning of the click event method.

Stopped on Breakpoint in Click Event Method

There are two ways to step through code in Visual Studio, Step Over a method (F10) and Step Into a method (F11). When you have hit a breakpoint as we have, if you press F10 on a line of code with a method on it, that means you want to step over that method. What that means in layman’s terms is you are telling Visual Studio, “Execute that Method, but I don’t want to go into it.” If you Press F11 on a line of code with a method on it to Step Into a method, you are telling Visual Studio, “Take me to the beginning of that method so we can walk through it line by line. At the End of that method, bring me back here.

When you are on a line without a method on it, as shown in the image above, it doesn’t matter whether you use F10 or F11.

Crazy Debug Menu

Now I have to admit that when I open my Debug menu, I am baffled because the keyboard shortcuts shown in the menu are different from what I and every developer I have known for years use. I guess I never really paid that much attention to it. Apparently you can use F8 for Step Into and Shift+F8 for Step Over. I can’t speak for everyone else, but everyone I know uses F10 and F11 for Step Over and Step Into respectively.

Ok, since we are currently sitting on a breakpoint without a method, go ahead and press F11 one time. This will cause the Yellow Arrow to jump to the first executable code, which is CreateNewBox(). It skips comments and variable declarations.

Executing CrateNewBox() Next

The Yellow Arrow points to the next line of code to execute, so the CreateNewBox method has not executed yet as shown in the image above.

If we press F10 (Step Over) here, the method will execute, but we will not Step Into the method. Go ahead and Press F10 here.

Next Line to Execute After Pressing F10

Ok, so CreateNewBox executed, but we did not get to inspect the CreateNewBox method. Sometimes if you are debugging a large program, you do not want or need to branch out to a bunch of methods, so you would press F10 to step over them.

Now, click the Yellow Arrow and Drag it back up to the CreateNewBox method. Yes, you can do that in Visual Studio. We now have a chance to Step Into this method without having to restart the program.

Now that you are on the CreateNewBox row of the Click Event method, press F11 to step into the method. You will jump to the top of the CreateNewBox method. Press F11 and you will jump down to the if Expression.

Execution Paused at if Expression

Now if you hover your mouse over the Text properties of each of the textboxes, you will see the values that you entered into the textboxes.

Hovering Mouse Over Text of txtLength Text Box

You can also hover your mouse over iLength and the other integer variables to see that they are all 0. You should also hover your mouse over the TryParse methods to see that they are all returning a boolean (true or false) value depending on whether or not it successfully parses the text and can convert it to an integer.

Intellisense Description of TryParse Method

Of course the text in the image above is tiny, but you can see it better in your Visual Studio if you are following along.

I will explain what this if is doing.

  • If the TryParse can convert txtLength.Text property to an integer
  • and the TryParse can convert the txtWidth.Text property to an integer
  • and the TryParse can convert the txtHeight.Text property to an integer
  • and the TryParse can convert the txtBox_X.Text property to an integer
  • and the TryParse can convert the txtBox_Y.Text property to an integer

By the way, && means and in C#.

If we can convert all 5 textbox values to an integer, then all 5 TryParse methods return true and the code in the if block will execute. If one or more TryParse methods return false, meaning we did not enter an integer value in one or more textboxes, then the code in the if block will not execute.

Any text that successfully parses to an integer, comes OUT of the TryParse method as an integer assigned to the appropriate variable.

Press F11 while the code is on the if Expression. If all 5 TryParse methods return true, the code will stop just inside of the if block.

Code Execution is Inside if Block

According to the Yellow Arrow in the image above, we are inside the if block, which means that all 5 TryParse methods returned true. Now we are getting ready to make a new Box…finally!

Hover your mouse over the integer variables which are acting as parameters to the Box class. You will see the integer values assigned to them by the TryParse method. Press F11 to jump down to the Box box = new Box line.

Intellisense Showing How a Box is to be Constructed

If you hover your mouse over the word Box to the right of the new keyword, you will see a hint showing the correct order of the variable parameters. This order is defined by the order of the variables in the Box Class constructor.

If you hover your mouse over the box variable, you will notice that it is null. This is because it hasn’t been initialized with a value yet.

Showing that box is null Before initialization

Press F11 and we will step into the Box Class constructor.

Stepping into Box Class Constructor

Hover your mouse over each of the integer parameters inside the parenthesis and you will see that they are equal to the values from the textbox Text properties. We passed those values from the MainForm class into the Box class via the constructor.

Showing Constructor Parameter Value

Notice that the m_iHeight and all of the other class member variables currently have their default values of 0. They haven’t been assigned the constructor parameter values yet.

Showing Class Member Variable Values Before they are Assigned Inside the Constructor

If we press F11 and step down to the end of the constructor, we will see that the class member variables will all get the values of their corresponding constructor parameters.

Showing Class Member Variables After Assignment

Now look above the Box Constructor and hover your mouse over the same Class Member variables and notice that they also hold the assigned values. Then look at the same variables inside the Draw method. They hold the same values. This is because these variables are accessible to the entire class.

Showing Class Member Variable Value After Assignment at Declaration Point
Showing Class Member Variable Value After Assignment in Draw Method

The reason these variables are accessible everywhere is that they were declared at the class level, as opposed to being declared inside the constructor or inside of a method.

Ok, press F11 to leave the constructor.

Now we go back to the box initializer. Press F11 to move down past the initializer. You can now see the value of box. Hover your mouse over the box (all lowercase) variable and then open the white arrow that appears.

Value of new box

If you cannot inspect the properties like this, the other option is to add box to your watch list. Right click box (all lowercase) and click Add Watch.

Adding box to Your Watch List

A new window should open at the bottom of Visual Studio and you should see the box variable. If box is collapsed, click the little arrow to the left of it.

box in the Watch List
Watch List Expanded

Hover your mouse over m_myBoxes and you will discover that it is an empty list. Alternatively, you could also add m_myBoxes to your watch list.

Press F11 one time and your box will be added to your m_myBoxes list.

m_myBoxes with 1 Box

m_myBoxes now is a list of 1 Shapes.Box. Notice that it is index 0 in the list. Now press F5 and let’s add another box with different values. Type new integer values in the text boxes of your choice.

My new Values

Set a breakpoint right below the m_myBoxes.Add line.

New Breakpoint to Allow Inspection of List

Click the Draw button and stop on our new breakpoint so we can look at the list with 2 boxes. Feel free to step through the code again on your own and inspect variables.

List With 2 Boxes

This is what the list looks like the second time around. Notice that it has 2 distinct boxes in it. This can go on and on forever.

Lets Draw these Boxes on the Form

There is a Windows Forms Event called Paint. This event occurs automatically when a control is re-drawn. See here for more information. We will access the MainForm Paint event. Select the form Design View tab.

Then select the actual Form to select it. You will see MainForm at the top of the properties window. Then in the propeties window, select the Events Lightning Bolt button to view the Form Events that are available. Find the Paint Event and double click it.

Finding the Form Paint Event

When you double click on the Paint row of the Form Events listing, Visual Studio will create an empty Paint Event method for you in the code.

private void MainForm_Paint(object sender, PaintEventArgs e)
{
    // All code inside this method will run
    // when the form is repainted.

When the form is repainted, we want the boxes that are present in our list of boxes, if any, to be drawn. We want the boxes to be drawn on the form drawing surface, which we get from the e variable in the PaintEventArgs of our Paint method.

Let’s create a new Method called DrawBox that accepts the PaintEventArgs as a parameter. We will call this method from the Paint event method and pass e to it.

private void MainForm_Paint(object sender, PaintEventArgs e)
{
    // All code inside this method when the
    // form is repainted.

    if (m_myBoxes.Count > 0)
    {
        DrawBox(e); 
    }
}

private void DrawBox(PaintEventArgs e)
{
    foreach (Box myBox in m_myBoxes)
        myBox.Draw(e.Graphics);
}

When the form is being repainted, a drawing surface called Graphics will be created in the PaintEventArgs, called e. The PaintEventArgs are passed to the DrawBox method. The DrawBox method accepts an argument of type PaintEventArgs, which we also call e for simplicity sake. Note that we are only calling the Drawbox method if our list contains at least 1 box object.

Inside the DrawBox method we will iterate over our list of Box objects that are contained in our m_myBoxes list. As we iterate over the list, we will reference each box as myBox. myBox is an instance of the Box class. The Box class contains a public method called Draw. myBox.Draw is us executing that method.

public void Draw(Graphics graphics) //Method
{
    /*
        * Obtained from 
        * https://www.daniweb.com/programming/software-development/threads/369044/drawing-cubes-in-c-using-system-drawing
        */
    Point origin = new Point(m_iOriginX, m_iOriginY); //Location of Box
    Pen pencil = new Pen(Color.Blue, 1f); //Blue pencil
    Rectangle R = new Rectangle(origin.X, origin.Y, m_iWidth, m_iHeight);
    graphics.DrawRectangle(pencil, R); // Draw Rectangle

    graphics.DrawLine(pencil,
                        origin.X, origin.Y,
                        origin.X + m_iLength,
                        origin.Y - m_iLength);// Top left edge

    graphics.DrawLine(pencil,
                        origin.X + m_iLength,
                        origin.Y - m_iLength,
                        origin.X + m_iWidth + m_iLength, origin.Y - m_iLength); //Top back width

    graphics.DrawLine(pencil,
                        origin.X + m_iWidth + m_iLength,
                        origin.Y - m_iLength,
                        origin.X + m_iWidth,
                        origin.Y); //Top Right Edge

    graphics.DrawLine(pencil,
                        origin.X + m_iWidth + m_iLength,
                        origin.Y - m_iLength,
                        origin.X + m_iWidth + m_iLength,
                        origin.Y - m_iLength + m_iHeight); //Back Right Edge

    graphics.DrawLine(pencil,
                        origin.X + m_iWidth + m_iLength,
                        origin.Y - m_iLength + m_iHeight,
                        origin.X + m_iWidth,
                        origin.Y + m_iHeight); //Bottom Right Edge
} //Closes Draw Method

As you can see, the Draw method accepts the Graphics object, which is the drawing surface from the PaintEventArgs. This drawing surface is the surface of MainForm, so each box will be drawn on the MainForm.

I think it will be easier to see if we step through the code. Clear any existing breakpoints by clicking them to toggle them off, or you can go to the Debug Menu and select Delete All Breakpoints.

Set a breakpoint on the DrawBox(e) line of the Form Paint method.

Breakpoint in Paint Method

Click the Green Arrow Start button , or press F5 to run our application. Ensure that you are in Debug mode and not Release mode.

Start in Debug Mode

Enter some integer values for a box.

If you have a second monitor, move the running form over to the monitor that Visual Studio is not running on to make it easier to see what is being drawn on the form as we step through the code. Alternatively, you can arrange Visual Studio and the running form so that they do not overlap before you click the Draw button.

Now click the Draw button. One new Box object has been added to our list. Our list has a count greater than 0, so we have stopped at our breakpoint inside the if statement of our Paint method.

While we are paused, hover your mouse over the e to view the values that pop-up in the tooltip. There are 2 e‘s in the Paint method. One is in the Paint Method parameters, and the other is inside the Drawbox(e) method call where we are paused. They are the same e.

Press F11 one time to step into the DrawBox method. Hover your mouse over the 2 e’s in the Drawbox method. They are different than the e’s that were in the Paint method, by they have the same value. This is because they were passed to the Drawbox method by value, which is the default way of passing arguments in C#. The important thing here is that e is the same type and has the same value as the e from the Paint method.

Press F11 a few times until you get down to the myBox.Draw(e.Graphics) line.

Stopped in DrawBox method

From here, we can inspect myBox. It will contain the dimensions and drawing location that we specified. Right click myBox and add it to your watch list.

myBox in the WatchList

Now press F11 so that we can step into the Draw method of the Box class. Once you are inside the Draw method, you can inspect the values of the height, width, length, and origin variables and you will see that they are what you supplied on the form.

Press F5 until you get past the graphics.DrawRectangle method. Now look at the running form, not the form in Design View. There should be an icon down in your task bar that represents the running application.

What you will notice is that actually, nothing is drawn on the form. We need to add a line of code to the btnDraw click event method. Go ahead and stop the application from running and then add this.Refresh(); to the click event method.

private void btnDraw_Click(object sender, EventArgs e)
{
    // all code in this method will execute 
    // when the Draw button is clicked

    CreateNewBox();
    this.Refresh();
}

this is actually a keyword in C# that represents the MainForm in this case. We need to refresh the form in order to see the results of the drawing operations. Run the application again and enter some values and step through the code again. Don’t forget to move the running form over to another monitor if possible before you click the Draw button.

Stop after the Rectangle has been drawn.

Rectangle on Form

Continue to press F11 as you draw each Line and you will see the Box being constructed.

Box Under Construction

After this box is fully drawn, go change the values of the box on the form and draw a second box, and a third box to see what happens on the form. You will have 3 distinct boxes on your form, and your list will contain those 3 box objects.

Three boxes on the Form

Wrap Up

I know this was a long lesson. Hopefully you got something out of it. If you enjoyed it, Like my blog so that you will be notified when I release more. I will try to do at least one every week. If you have questions or comments, please leave a comment below, or you can email me in the Contact page.

Working with Buttons in Windows Forms

Buttons allow users to interact with a winforms application. The most popular event that is used for buttons is the click event.

An event is like a trigger for something to happen in the application. So it is like saying, “when this event happens, do this …”. So in this case, the event is that a button was clicked.

For our demonstration, we will create a simple winforms application that increments or decrements a counter (integer) that is displayed on a form.

A video of the demo is provided here, followed by step by step instructions.

Video of this Demo

Setup Your Environment

The first step is to launch Microsoft Visual Studio. If you do not have Visual Studio, see my post here, https://win-forms.com/2020/07/25/create-a-hello-world-winforms-application/ to learn how to download and install Microsoft Visual Studio and create your first Hello World application using Windows Forms.

Once Visual Studio is open, create a new project.

Create A new Project

Choose Windows Forms App (.Net Framework) C# as the template. Filter on C# Windows Desktop as shown in the image below.

Selecting Windows Forms type of Project

After you have selected the Windows Forms template, select Next. Name your project as ButtonDemo. I will be using .Net Framework 4.7.2 for this demo.

Name the Project

Click the Create Button. Once your project has been created, you will be presented with the blank Windows Forms template .

Blank Windows Forms Template

Rename our Form

Notice that our form gets the default name of Form1. It is good practice to name this to something more meaningful. When you start working on projects that contain several forms, you will have a hard time trying to keep track of each form and what they are used for if they are named Form1, Form2, Form3, etc.

Let’s name our form as MainForm to indicate that this is the form that will load when the application starts up. Right click Form1 in the Solution Explorer and click Rename. After you rename the form, press Enter.

Renaming Form1 to MainForm

Rename the Form Heading

Showing Form1 in Form Heading

Let’s change the heading for MainForm to display Main Form. Select the form by click on the form in design view. When the form is selected, you will see sizing handles on the form border and MainForm will be displayed at the top of the properties window.

Indications that Form1 is Selected

When MainForm is selected, you can find the Text property of the form in the properties window, as shown above, and change the text from Form1 to Main Form as shown below.

Form1 Text Property Now Displays Main Form

Add Controls to the Form

Open the Toolbox, which should be on the upper left edge of Visual Studio.

Location of the Toolbox in Visual Studio

The Toolbox contains all of the controls that are available in our chosen Framework, which is .Net Framework 4.7.2 in our case.

When the toolbox is open, drag 2 buttons and a label out onto the approximate middle of the form.

Label and Button in the Toolbox
Buttons and Label on the Form

Set Properties on the Controls

Now we need to change the Text Property of button1 and the Name Property of button1. Select button1 on the form by left clicking it 1 time. You will see sizing handles around the button when it is selected and you will see button1 at the top of the properties window.

button1 Selected and the Default Properties

With button1 selected, change the Text Property to -, the hyphen or minus symbol. Change the Name property to btnDecrement. btn means button. When we reference the button in code by the Name property, it will be easy for us to recognize that it is a button because the name begins with btn.

button1 Changed to Correct Properties

Now select button2 and make similar changes. Change the Tex Property to +, the plus symbol. Change the Name Property to btnIncrement.

btnIncrement Properties

Select the label1 control. Change the Name property to lblValue. Change the Text property to 0, the number zero. When the form first loads, we want it to display a default value of 0.

lblValue Properties
Completed Form Design

Click Events for the Buttons

An event is basically something that triggers some code to run. A click event “fires” when the user clicks the mouse on a control. a Key Down event fires when the user presses a key down. A Key Up event fires when the key is released. There are many other events that can be “Trapped“. If you want to execute some code when a particular event happens on a particular control, then you create an Event Listener. There are a few different ways to create an event listener. I will show you the 2 easiest ways to create button click event event listeners.

Create Button Click Events Method 1

Buttons are meant to accept clicks. The Click event is the default event for the button control. Double-Click btnDecrement on the form designer. You should see the MainForm code file open and you should see an empty click event method for btnDecrement.

Empty btnDecrement_Click Event Handler

Code that we want to execute when someone clicks btnDecrement belongs inside this method. What do we want to happen when someone clicks the decrement button? We want to decrement an integer by 1. To make it somewhat interesting, let’s add a condition that says our integer cannot go less than 0.

The first thing that we need is a variable to hold our integer value. We need to be able to access this variable from anywhere in our MainForm class. The reason for this is that we are going to be manipulating this variable from 2 different methods. One of the methods is the decrement button click event handler method. The other place is the increment button click event handler. I have not introduced you to passing variables from method to method yet, so we will make the integer variable accessible to the entire class for our demo.

In order for a variable to be accessible to the entire class, we need to declare it directly inside the class curly braces.

namespace ButtonDemo
{
    public partial class MainForm : Form
    {
        //This is where class level variables belong

        public MainForm()
        {
            InitializeComponent();
        }

        //You could also declare them here

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

        //You could also declare them here
    }
}

I have added comments to indicate where class level variables normally go, but also to show alternate locations. Basically, as long as you do not declare them inside methods or constructors, you are usually OK.

public partial class MainForm : Form
    {
        //This is where class level variables belong
        int m_iValue;

        public MainForm()
        {
            InitializeComponent();
        }

        //You could also declare them here

        private void btnDecrement_Click(object sender, EventArgs e)
        {
            
        }
        //You could also declare them here
    }

We have declared an integer variable at the class level called m_iValue. The m means that it is a member of the class. This distinguishes it from local variables, which would be declared inside of methods. The i means that it is an integer. This way, even if I have hundreds or thousands of variables of various types in an application, I can instantly recognize that this variable is an integer. That is important because I need to know the type in order to know how to use it in various places in code.

Add Code to the Button Click Events

private void btnDecrement_Click(object sender, EventArgs e)
{
    if (m_iValue > 0)
    {
         m_iValue--;
    }
    lblValue.Text = m_iValue.ToString();
}

Every time someone clicks the btnDecrement button, the code in the btnDecrement click event handler will run. By default, the value of a newly declared integer is 0. So when we first run our program, the value of m_iValue will be 0. Since m_iValue is not greater than 0, m_iValue will not decrement. In order for the code inside the if statement to execute, the condition inside the parenthesis has to evaluate to true. Therefor, m_iValue must be greater than 0 in order for m_iValue to be decremented. m_iValue– means decrement the value of m_iValue by 1. Our if statement prevents m_iValue from going negative.

Next, lblValue.Text = m_iValue.ToString(); populates the Text property of the label on our form with the text version of the integer value. We must convert the integer value to a string. A string is a text data type as opposed to numbers. The Text property can only be assigned a text value. This is why we have to use ToString().

Go back to the form designer. We are going to use a different technique to create the click event for btnIncrement. Single click btnIncrement to select it. Now click the lightning bolt icon on the properties window.

btnIncrement Event Listing Arranged by Category

Notice in the image above that I have selected the lightning bolt. These are the events that are available for the button. Also notice that my view is by category instead of alphabetical (Green circle on the left). So in this view, the default event (Click) is at the top of the list. Double click the word Click or the empty space to the right of the word Click. A new empty event will be created in the MainForm class code file.

public partial class MainForm : Form
{
   //This is where class level variables belong
   int m_iValue;

   public MainForm()
   {
      InitializeComponent();
   }

   //You could also declare them here

   private void btnDecrement_Click(object sender, EventArgs e)
   {
      if (m_iValue > 0)
      {
         m_iValue--;
      }
      lblValue.Text = m_iValue.ToString();
   }

   private void btnIncrement_Click(object sender, EventArgs e)
   {

   }

   //You could also declare them here
}

Now we just need to add our code for the btnIncrement event handler. It will be similar to the decrement event handler. We will enforce a rule that the value cannot go above 10.

private void btnIncrement_Click(object sender, EventArgs e)
{
   if (m_iValue < 10)
   {
      m_iValue++;
   }
   lblValue.Text = m_iValue.ToString();
}

We check to ensure that the value of m_iValue is less than 10. If that condition is true, the code inside the if statement will run, which means the value of the variable will increment by 1. Then the Text property of the label will be set to the value of the m_iValue variable (converted to a string).

Lets Run Our Program

Run the Program

Click the green Start Arrow or press F5 on your keyboard to run our program. After a few seconds to a few minutes, depending on your computer, you should see your form pop up. If not, go back and double check your code against this tutorial. You should not have anything underlined in red in your code. If you do, those red underlines are where the problem is. You may have forgotten a semi-colon or a brace or a parenthesis, or the some code may not be in the proper case. It is all case sensitive.

Full Code

If you did not see any errors and your form loaded, try clicking the buttons to ensure that you see a value incrementing and decrementing.

Application Running

If you have any questions or comments, please comment below and I will get back to you.

Create a “Hello World” Winforms Application

The only tool that you need to create a Winforms application is Visual Studio. Some die-hard coders would probably tell you that they could do it with Windows Notepad, but I prefer to use Microsoft Visual Studio, and that is what I will use in all of my blog posts.

Visual Studio Community Edition is free, but their are also some paid editions available that offer additional features. Visual Studio can be downloaded from https://visualstudio.microsoft.com/vs/.

Installing Visual Studio

Navigate to https://visualstudio.microsoft.com/vs/ and download the Visual Studio edition that you want to work with. I use Visual Studio Community Edition for personal projects and that works well for me. At work, I use Professional Edition, but the only reason for that is because of the licensing requirements. I do not choose Professional because of the additional features. Community Edition has everything I need.

Visual Studio Download Page

By default, the installer should be downloaded to you Downloads folder. Launch the installer.

Choose Edition to Install

Click the Install button for the edition that you want to install. Select the .Net desktop development workload as shown below. Notice that I have removed some of the default options from the Optional components pane to the right, and I elected to install .Net Framework 4.61. The reason I chose this framework is because I use it a lot. You do not have to install .Net Framework 4.6.1. I will be using .Net Framework 4.7.2 for this demo.

Installation Choices

You may choose to install any or all additional workloads and components. At a minimum, install .Net desktop development and .Net Framework 4.6.1 to follow along with this demo. Once you have made your choices, click the Install button in the lower right corner. Depending on your system, this installation could take a little while. By the way, you can always re-run this installer to load additional workloads or components, or remove them.

Launch Visual Studio

If Visual Studio does not automatically launch after it finishes installing, you can find it in your Start Menu. Notice that the installer is also in the Start Menu.

Visual Studio in the Start Menu

Go ahead and launch Visual Studio.

Let’s Create Our Hello World Project

Create a New Project Button

As you can see under Get Started in the image above, you have several options for getting started on new or existing projects. One of the options is Create a New Project. Choose this option.

Choosing the C# Windows Desktop Forms App Template

Right away when you stare at all of the possible choices for the type of app to create, it may seem a little overwhelming. But there are 3 combo boxes at the top of the list that will help you narrow down the choices. Choose, as I have, C# for the programming language, Windows for the Platform type, and Desktop for the Project Type.

If you installed additional Workloads, your list may look different than mine. I have the correct project template circled in green in the image above. Select “Windows Forms App (.Net Framework)” and then click the Next button.

Naming Your Project

Type your Project Name as Hello World. Change the Framework to .Net Framework 4.7.2 if it does not default to 4.7.2. Once this is done, click the Create button to create our project.

Exploring our Project / Solution

Initial Project View

I don’t want to get into too much detail in this post because this post is just supposed to be a Hello World demo. But I do want to explain a little bit about what you are seeing as shown in the image above.

At the very top of the Solution Explorer, you see Solution ‘Hello World’ (1 of 1 project). The solution is the container for all of the related projects. Each project will compile to a single Executable (i.e. Hello World.exe) or DLL (i.e. Hello World.dll) when the solution is compiled. The default is to compile to an executable and that is what we are doing. Our solution currently contains 1 C# project called Hello World. The project also contains 1 form called Form1 and 1 class file called Program.cs.

Program.cs is the main entry point of the project. This means the when we start debugging the project, the code in Program.cs will execute first. There is code in Program.cs that will launch Form1.

App.config just contains some basic configuration info for the Hello World project. Properties are the project properties.

Let’s Rename Our Form1 to MainForm

I despise default values. Visual Studio named our form as Form1. If you had a project that contained several forms, it would be hard for any developer to keep track of the purpose of each form if they were named Form1, Form2, Form3, etc. So whenever you create a new form or button or text box, or whatever, please name it something meaningful to make it easier to remember what it is for.

Renaming Form1

Right click Form1 in the Solution Explorer and select Rename as shown in the image above. Name it MainForm with no spaces between Main and Form.

Form1 Renamed to MainForm

Displaying Hello World on Our Form

If the blank MainForm is not displayed in Design View as shown below, double click MainForm to open it in Design View.

Open MainForm in Design View if Not Already Open

Once the MainForm is open in Design View, click the background or border of the form to select it. You will see sizing handles on the right and bottom edge of the form when it is selected. You will also notice that MainForm is displayed at the top of the Properties window as shown in the image above.

When the form is selected, look at the Properties window and find the Text property. It should say Form1.

MainForm Text Property Incorrectly Says Form1

We need to change this to Hello World. Notice that in the top left border of our MainForm it says Form1. Type Hello World in place of Form1 and press Enter. Now the top left form border says Hello World.

Add a Label Control

On the left edge of the Visual Studio window, you should see the Toolbox.

ToolBox Normal Location

If you do not see it there, go to the View Menu and Select Toolbox. Once you see it attached to the edge of the Visual Studio window, click to open it. The Toolbox contains all of the available form controls such as labels, buttons, text boxes, etc.

When the Toolbox has opened, you can see that there are various categories of controls. If you expand All Windows Forms, you will be able to view all of the available controls.

Some of the Windows Forms Controls

The image shows some of the available controls. The list is pretty long.

Find the Label Control and drag it to the middle of the form somewhere and then drop it.

Label in the Toolbox
Label on the MainForm

Ok, the label is on the MainForm with a default text property of Label1. The label should also be selected by default. If you deselected it, please click the label on the form and confirm that Label1 is selected at the top of the properties window.

Label 1 Selected

When you have confirmed that Label1 is selected, change the Text property to Hello World! Now find the Font Property and open it by clicking the plus sign. Change the font size to 24 and position the label at the middle of the form by dragging it.

Setting Font Size

Let’s Run Our Application!

At the top of your Visual Studio window, you should see Green Arrow button labeled Start. If you do, click it to run your application. If not, go to the View Menu and select Toolbars > Standard to display the Standard Toolbar, or press F5 to run it if you don’t want to display the Standard Toolbar.

When the application finishes compiling, you should see your form pop up and display Hello World in the middle of your form.

Running Application

You can click the Minimize button in the upper right of the form to minimize the form, or the maximize button to maximize it. Of course you can close the form by clicking the X. Closing the form also stops the application from running. You can also stop the application from running by clicking the red stop button in Visual Studio.

Stopping the Application

Where Is Your Executable?

When you started the application, an Executable file was created which represents your application. In your Solution Explorer, select the top level solution node. Look in the properties window for the path to the solution file.

Path to the Solution File

Navigate to that folder.

Solution Folder

You can open your solution by double clicking the Hello World.sln file, but next time you open Visual Studio, this solution should show up as a recent solution.

Now navigate into the Hello World folder. This is the Hello World project folder.

Project Folder

Some of these files should seem somewhat familiar to you. You see these file in the Solution Explorer. Now open the bin (stands for binaries) folder. You will see 2 folders. One is Debug, the other is Release. We have only run our project in Debug mode, so the Debug folder is the only one that will have files right now. If we were to go back into Visual Studio and change Debug to Release and run it, then the Release folder would be populated. For now, navigate to the Debug folder.

Debug Folder Contents

There is your executable. Since this is a debug version of the executable, you should not distribute it. Any executables or dll’s that you want to distribute should be compiled in Release mode.

If you have any questions or comments, please leave a comment below.

Introduction to Scope in C#

What is scope?

The term Scope is all about the parts of an application where the same instance of a variable is accessible.

Refer to the Box class below. Notice the Curly Braces, i.e. {This text is inside of opening and closing curly braces}. The Member variables m_iLength, m_iWidth, and m_iHeight are members of the class called Box. They have scope within the Box class. We know this because they are declared directly inside the class Box opening brace. We know that they are declared directly inside of class Box because the name of the variables is preceded by a type keyword called int. We are declaring that m_iLength is a type int (integer). We are also declaring that it is private, which means that it is not accessible outside of Box class.

Notice that we have also declared the variables Length and Width at the class level. We have declared that they are integers and that they are public. We declared them as public because we want them to be accessible outside of the Box class. This means that if we are working in another class and we create an instance of the Box class, we will be able to get or set m_iLength via the Length property, which is a public variable.

If we declare a variable inside of a method, then that variable only has scope inside of that method. Furthermore, if we declare a variable inside of a for loop, for example, that variable has scope only within that for loop. This means that outside of that for loop, we will not be able to access that variable because it is out of scope. Out of scope means that we will not be able to read the value of that variable or change the value of that variable. A private variable only has scope within the immediate set of curly braces that it is declared in.

    namespace Shapes
    {// Beginning of namespace
        class Box
        {//Beginning of class
            private int m_iLength; //member variable accessible to this entire class
            private int m_iWidth; //member variable accessible to this entire class
            private int m_iHeight; //member variable accessible to this entire class

            public int Length //property accessible to any class that instantiates this class
            {
                get {return m_iLength;}
                set {m_iLength = value;}
            }

            public int Width //property accessible to any class that instantiates this class
            {
                get {return m_iWidth;}
                set {m_iWidth = value;}
            }

            public int Height //property accessible to any class that instantiates this class
            {
                get {return m_iHeight;}
                set {m_iHeight = value;}
            }   

            public Box()
            {
                //Default Constructor
            }

            public void DecreaseBoxHeight() // method 
            {// accessible to any class that instantiates this class because it is public
                if(m_iHeight > 1) 
                {
                    m_iHeight--; //decrease height
                }
            }
        }//End of class
    }//End of namespace
namespace example
{
    class scopeExample
    {
        private void myFirstMethod()
        {
            int firstMethodVariable = 5;
        }

        private void mySecondMethod()
        {
            int secondMethodVariable = 0;
            secondMethodVariable = firstMethodVariable; // this won't work
        }
    }
}

The scopeExample class will not compile because there is an error in mySecondMethod. firstMethodVariable is not accessible from inside of mySecondMethod because firstMethodVariavble was declared inside of myFirstMethod. Therefor, firstMethodVariable has scope in myFirstMethod, but not in mySecondMethod.

Classes and Objects

What is a Class?

In the simplest terms, a Class defines an Object. A Class is used to define the characteristics of an Object. In other words, a Class describes what an object is made of and what it can do.

The characteristics of a class are defined by its properties. What it can do is defined by its methods. Consider the following Box class. It has the following three properties:

  • Length
  • Width
  • Height

This Class has one method called DecreaseBoxHeight. This means that it can do one thing right now, and that is Decrease the height of the box. More methods can easily be added to manipulate the width and length in a similar fashion.

namespace Shapes
{
        class Box
        {
            private int m_iLength; //member variable
            private int m_iWidth; //member variable
            private int m_iHeight; //member variable

            public int Length //property
            {
                get {return m_iLength;}
                set {m_iLength = value;}
            }

            public int Width //property
            {
                get {return m_iWidth;}
                set {m_iWidth = value;}
            }

            public int Height //property
            {
                get {return m_iHeight;}
                set {m_iHeight = value;}
            }   

            public Box()
            {
                //Default Constructor
            }

            public void DecreaseBoxHeight() // method
            {
                if(m_iHeight > 1)
                {
                    m_iHeight--; //decrease height
                }
            }
//End of method
        }
//End of class
    }//End of namespace

What’s the difference between a Class and an Object?

As stated before, a Class defines an Object. A Class is not an Object. Another way of looking at it is that a Class is a blueprint for an Object. A class cannot be used unless you instantiate it (create an instance of it). When you create an instance of a Class, you have an Object that you can use.

The one exception to the statement that I just made, “A class cannot be used unless you instantiate it“, is with static classes. You can not instantiate a static class. If you create a static class, you just use it. I will talk more about static classes in another post.

Don’t worry if this doesn’t make sense right now. We will work through an example.

Let’s Create a Box!

If we want to create a Box, we have to Instantiate it, or create a NEW Box. We do that using the new keyword like this.

Box cBox = new Box();
cBox.Length = 10;
cBox.Width = 10;
cBox.Height = 10;

We have created an Instance of a box called cBox. Notice that we used the new keyword to create an Instance of the Box Class. The Object that was created from the Box class is represented by the variable cBox. cBox is a variable that was created to represent the Box class. We could have used any name for the variable, but I chose cBox because it is easy to recognize in code. To me, it means class box, where the c means class.

Have a look at the full code for the Box class. Notice that the name of the class is Box. Since the Box class defines a Box, when we want new boxes, we have to create new boxes.

We went on to define the dimensions of cBox by setting the Length, Width, and Height to 10, so we have a Cube shape. Length, Width, and Height are public properties of the Box Class. When we Set those Properties, we are also setting values on m_iLength, m_iHeight, and m_iWidth. Notice the following properties in the Box class that Set the values of m_iLength, m_iHeight, and m_iWidth.

public int Length //property
{
   get {return m_iLength;}
   set {m_iLength = value;}
}

public int Width //property
{
   get {return m_iWidth;}
   set {m_iWidth = value;}
}

public int Height //property
{
   get {return m_iHeight;}
   set {m_iHeight = value;}
}   

We can decrease the height of cBox by calling its method DecreaseBoxHeight.

Manipulate cBox by Calling a Method.

cBox.DecreaseBoxHeight();

Since cBox represents a Box object, we can access it’s public properties and methods. Notice that DecreaseBoxHeight is a public method.

public void DecreaseBoxHeight() // method
{
   if(m_iHeight > 1)
   {
      m_iHeight--; //decrease height
   }
}
//End of method

Powered by WordPress.com.

Up ↑

%d bloggers like this: