You are on page 1of 36

 

6. The C# code in .Net Applications


 
In the previous chapter, we had explored all that was required to be learnt and discovered
about C#, in order to understand the code generated by the Framework. A crucial point that
screams for attention is, that any application built in Visual Studio.Net with Project Type as
Visual C#, eventually is converted into C# code. In this chapter, we will build applications in
Visual Studio.Net, and at every stage thereon, we shall explain the code generated by the .Net
Framework. We could have written the same code manually, but it certainly gives our
productivity a boost, if the code is automatically generated by the system.
 
Let us revert back to Visual Studio.Net, to create a new application. As always, click on menu
File - New - Project. In the dialog box, select Visual C# Project in Project Type pane, and
Windows Application in the Template pane. Enter the name z10, and ensure that the location
is set to c:\mukhi. On pressing F5 to run the application, you will come across a completely
blank window.
 
When you navigate into the folder c:\mukhi\z10, you will encounter a large number of files,
created by this framework. One of the many files created, is named as Form1.cs. This is similar
to the .cs file, which was created in the previous chapter. Now, run the compiler using the
command
 
>Csc Form1.cs
 
The compiler creates an exe file named Form1.exe, which when executed, reveals the same
window, as is seen with the F5 command. The program Form1.cs has been generated by Visual
Studio.Net, which internally calls the C# compile and creates the executable file. Pressing F5
runs the executable. Let us now attempt at understanding the code, that gets generated in
Form1.cs.
 
Form1.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
 
namespace z10
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
 
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
 
//
// TODO: Add any constructor code after InitializeComponent call
//
}
 
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
 
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.Size = new System.Drawing.Size(300,300);
this.Text = "Form1";
}
#endregion
 
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}
 
We hope to be able to refresh your memory by reiterating that, the above program has been
written by the C# compiler, and not by us. The file reveals a large number of statements
beginning with the term 'using'. For those of you who tuned in late, the 'using' statements are
inserted to ease the typing effort. The name of a namespace is provided after the 'using'
keyword, so that the namespace is not required to be inserted before each 'class.function name'
combination. As the project has been named z10, the entire C# program is depicted as
enclosed within the namespace of z10. Since the solitary role of a namespace is to ensure that
the class names in one project, do not clash with class names in the other projects, it can
safely be overlooked.
 
You may recollect that in the last chapter, we had gathered that any line beginning with three
slashes, is an XML comment. This program appears very large, due to the comments inserted
at every possible nook and corner. More often than not, comments are not of much utility,
since they are computer generated; and thus, lack the essential human touch. In future, we
will strip-off all comments, before displaying the code.
 
A class known as Form1, which is derived from the class Form, contains all the code required
for the current project. In spite of employing the term 'using', which includes
System.Windows.Forms, the code generated, still contains the full name of the class. It is
absurd and illogical, but then; computers are not expected to generate code that makes perfect
sense. In the first place, an instance variable called 'components' in the class, has been
initialized to 'null', which represents no value. The 'private' modifier limits the access only to
the members of the current class.
 
The Run function, located in the Main function, is called after passing it an object, which is an
instance of Form1. The newly created object calls the constructor of the Form1 class, and then,
it calls the Run function. The constructor simply calls a function named InitializeComponent.
 
But prior to this, study the square brackets above the Main function closely. It represents an
'attribute'. Attributes have a range of functions, which undertake certain tasks, such as,
determining the wherewithal of generating the code with the aid of the compiler, or
documenting the classes in the executable file, etc. We shall not venture into the details of the
attribute [STAThread], however, for those burning with curiosity, it suffices to say that the full
form of STA is Single Threaded Apartment. It implies that, once a window is created in a
thread, it will not be permitted to switch to another thread. If you are unable to comprehend
the finer nuances of the above statement, then cheer up, you have company!
It is in this function, that all the form widgets get initialized. We employ this function, only in
the event of initializing the object components. The computer program that generated the code,
prefixed all the instance variables with the term 'this'. In this case, eliminating the term 'this',
does not affect the outcome. The class Form has a large number of instance variables, such as
Size and Text, which we are entitled to be used in the class Form1.
 
The Size variable or Size property, determines the size of the initial window, while the Text
property decides the title of the window. The 'this' keyword is optional. A point to be noted is
that, all properties have a default value. No sooner do we change a single property in the
Property window, a line gets inserted in the InitializeComponent function. The Size property is
initialized to a Size object, which is passed the width and height of the window in pixels. Thus,
a GUI is used to build applications and all actions get converted into C# code.
 
The next function called Dispose, can only be called by the system, as and when it is required.
A programmer does not enjoy the facility of calling it manually. We are completely aware about
the circumstances under which a constructor gets called. Further, we also know unequivocally,
that the Dispose function gets called, when the resources in the program are to be disposed off.
But, we are not aware as to when this disposal takes place; in other words, when is an object
going to die. In C#, unlike C++, there is no control at all, over the termination of an object. The
Garbage Collector is solely responsible for removing an object from memory; thereby, shielding
the programmer from carrying out any memory management chores. The Dispose function can
also be ignored, since it merely calls the Dispose function from the Components object and the
base class. Hence, the use of keyword 'base' can be explained. In our next display, we do not
intend to expose you to the Dispose function any longer.
 
Now, its time we got back to Visual Studio.Net. Double click on the form. As is always the case,
the Code Painter gets displayed. Now, press Ctrl+Home to move to the beginning of the page, or
scroll up till the first line is visible.
 

Screen 6.1
 
Screen 6.1 presents the code that is displayed in our window. Here, we discern a list of 'using'
statements and a minus sign, extending over an entire span of six 'using' statements. Now,
click on the minus sign, and observe your screen change its display, as shown in screen 6.2.
 

Screen 6.2
 
To our utter astonishment, all the 'using' statements vanish, and what is remnant is a plus
sign and the term 'using', with a series of dots as residues. Thus, the editor is conscious of how
it has to work with the C# language. It is not merely a word processor, but a word processor
that knows and discerns the C# programming language, better than we do. The words, also
known as keywords, that are a part of the C# language, are depicted in a different color. Also,
every separate entity begins with a minus sign. Now, click on the minus sign in front of class.
Screen 6.3 displays the Code Painter.
 
Screen 6.3
 
Clicking on the minus sign of the class, compresses it into a series of dots. This signifies that it
is the class that encapsulates all the code. We can compress any entity in C# and thereby,
remain at the level of detail we are comfortable with. With a small screen, we need to be very
selective about the level of detail that can be displayed. Now, incorporate a button onto the
Form Design and double click on it. The addition of a button, results in a variation in the code
also. The program is shown below.
 
Form1.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
 
namespace z10
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
this.button1.Location = new System.Drawing.Point(40, 64);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.AddRange(new System.Windows.Forms.Control[]
{ this.button1});
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void Form1_Load(object sender, System.EventArgs e)
{
 
}
 
private void button1_Click(object sender, System.EventArgs e)
{
 
}
}
}
 
The above program displays the code that is generated after the button is clicked. A large
portion of the code remains the same, as was noticed in the earlier program. Therefore, we
shall desist from harping upon it any longer. Besides, from now onwards, only relevant parts of
the code will be revealed, to avoid redundancy and confusion, and also to conserve paper.
 
The newly added button in the form is called button1. Therefore, an instance variable is
created with the same name, i.e. button1. The data type is Button, which is a class in the
Forms namespace. Any GUI code that needs to be executed before the window is displayed, is
always placed in the InitializeComponent function.
 
Any line that originates with the # symbol, is known as a pre-processor directive. The pre-
processor is a program that executes before the C# compiler commences its work. The #region
command displays a minus sign. If we click on it, the region which extends from this sign upto
the #endregion, collapses. The words displayed in the box, remain the same, as shown after the
#region directive. This is amply evident in screen 6.4.
 
Screen 6.4
 
The InitializeComponent function contains a large number of statements that deal with the
Button object. First and foremost, an instance of the button object is created, with the help of
the 'new' keyword. The function SuspendLayout, as the name itself suggests, does not execute
any code that deals with placement of controls or layout, until the function ResumeLayout is
called. Invariably, this is the very last function to be called. The Location property is initialized
to the position where the control is placed, and the name is the text displayed on the button.
The Click property is called a 'delegate' in C#, which is associated with a function that gets
called, each time the button is clicked. The name of the function is passed as a parameter to
the constructor of class named EventHandler.
 
There could be multiple buttons present in a form. Each of them would necessitate a separate
function, which is to be called when the button is clicked. Therefore, the approach adopted by
the programmers for determining the function name, is as follows: The name of the button,
followed by an underscore, followed by the word 'Click'. In this manner, distinct names are
assigned to each of the functions, since the names of the controls are always unique.
 
All this discussion proves to be inefficacious, unless we display a button on the screen. To
achieve this, the services of the AddRange function, belonging to the Controls object in the
Forms class, are employed. This function accepts an array of the Control datatype, which holds
widgets to be displayed. In this case, there is only a single button; however, in real life, there
could be numerous controls. This function is used to add multiple controls, simultaneously.
 
Thus, by using the Graphical interface, life becomes a lot more simpler, since we can eschew
the drudgery of manually entering a horde of new changes, embodied in the form. Imagine how
cumbersome it would be to write and re-write the code, each time the button is shifted, even a
little. A new value would have to be assigned to the Location property, every time the button is
moved.
Each time we double click on the Form, we are directed to a function called Form1_Load. This
is due to the fact that the property Load, belonging to the Form class, is assigned this value.
The code in the above function, is executed before the window is displayed, but after the
execution of the function InitializeComponent.
 
Everything about Visual Studio.Net is dynamic. Any change incorporated in the value of a
property in the Code Painter, gets reflected instantaneously. Locate the property called Text in
the Code Painter, which is shown as:
 
this.button1.Text = "button1";
 
Now, change it to the following:
 
this.button1.Text = "vijay";
 
Then, click on the Design Tab. Some processing takes place for a while, before the Form is
activated. In the form, the Text property changes to 'vijay' immediately. Now, add the following
line in the function InitializeComponent, just below the Location property:
 
this.button1.Size = new System.Drawing.Size(72, 80);
 
The moment we click on the Design Tab, the size of the button undergoes a transformation.
The Form Design and the Properties window also change. In the Properties window, the value
of Size changes immediately. In the Design, delete the button by selecting it, and then, pressing
the Delete key. Switch to the Code Painter, and you will witness that, all references to the
button named button1, have been removed from the code, including the ones entered by us.
However, the function button1_Click, does not get erased. There appears to be a bug in the
Beta copy of the product. We presume that this bug will be fixed in the final copy of the
product.
 
We have not saved anything so far. We would advise you against changing anything in the
Code Painter. Instead, you may use the Properties Window for this purpose. The C# compiler
couldn't care less about who has actually entered the code. It merely validates the syntax and
creates an exe file. This exe file is then executed, using the F5 option.
 
The next example relates to the code generated by the Framework when data is displayed from
a database. So, select the Data tab from the toolbox, and bring an OleDbDataAdapter into the
form. In case you are unable to recollect the steps, peruse through Chapter 2 of this book.
Select the data connection of VMUKHI.Northwind.dbo, and insert the following SQL statement:
 
SELECT CustomerID, CompanyName, ContactName FROM Customers
 
In the Form, the OleDbDataAdapter control also adds another control called
oleDbConnection1. Switch to the Code Painter and observe the modifications made to the code.
 
private System.Data.OleDb.OleDbDataAdapter oleDbDataAdapter1;
private System.Data.OleDb.OleDbCommand oleDbSelectCommand1;
private System.Data.OleDb.OleDbCommand oleDbInsertCommand1;
private System.Data.OleDb.OleDbCommand oleDbUpdateCommand1;
private System.Data.OleDb.OleDbCommand oleDbDeleteCommand1;
private System.Data.OleDb.OleDbConnection oleDbConnection1;
 
At first, six instance variables are created. Apart from the oleDbDataAdapter1 and
oleDbConnection1, four more variables are created, each belonging to the data type
OleDbCommand. Now, expand the region 'Windows Form Designer generated code', and view
the revised code in the InitializeComponent function.
 
private void InitializeComponent()
{
this.oleDbDataAdapter1 = new System.Data.OleDb.OleDbDataAdapter();
this.oleDbSelectCommand1 = new System.Data.OleDb.OleDbCommand();
this.oleDbInsertCommand1 = new System.Data.OleDb.OleDbCommand();
this.oleDbUpdateCommand1 = new System.Data.OleDb.OleDbCommand();
this.oleDbDeleteCommand1 = new System.Data.OleDb.OleDbCommand();
this.oleDbConnection1 = new System.Data.OleDb.OleDbConnection();
this.oleDbDataAdapter1.DeleteCommand = this.oleDbDeleteCommand1;
this.oleDbDataAdapter1.InsertCommand = this.oleDbInsertCommand1;
this.oleDbDataAdapter1.SelectCommand = this.oleDbSelectCommand1;
this.oleDbDataAdapter1.TableMappings.AddRange(new System.Data.Common.DataTableMapping[] {
new System.Data.Common.DataTableMapping("Table", "Customers", new
System.Data.Common.DataColumnMapping[] {
new System.Data.Common.DataColumnMapping("CustomerID", "CustomerID"),new
System.Data.Common.DataColumnMapping("CompanyName", "CompanyName"), new
System.Data.Common.DataColumnMapping("ContactName", "ContactName")})});
this.oleDbDataAdapter1.UpdateCommand = this.oleDbUpdateCommand1;
this.oleDbSelectCommand1.CommandText = "SELECT CustomerID, CompanyName, ContactName
FROM Customers";
this.oleDbSelectCommand1.Connection = this.oleDbConnection1;
this.oleDbInsertCommand1.CommandText = "INSERT INTO Customers(CustomerID, CompanyName,
ContactName) VALUES (?, ?, ?);"+
"SELECT CustomerID, CompanyName, ContactName FROM Customers WHERE (CustomerID = ?)";
this.oleDbInsertCommand1.Connection = this.oleDbConnection1;
this.oleDbInsertCommand1.Parameters.Add(new System.Data.OleDb.OleDbParameter("CustomerID",
System.Data.OleDb.OleDbType.WChar, 5, System.Data.ParameterDirection.Input, false,
((System.Byte)(0)), ((System.Byte)(0)), "CustomerID", System.Data.DataRowVersion.Current, null));
this.oleDbInsertCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("CompanyName", System.Data.OleDb.OleDbType.VarWChar, 40,
System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)),
"CompanyName", System.Data.DataRowVersion.Current, null));
this.oleDbInsertCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("ContactName", System.Data.OleDb.OleDbType.VarWChar, 30,
System.Data.ParameterDirection.Input, true, ((System.Byte)(0)), ((System.Byte)(0)),
"ContactName", System.Data.DataRowVersion.Current, null));
this.oleDbInsertCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("Select_CustomerID", System.Data.OleDb.OleDbType.WChar, 5,
System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "CustomerID",
System.Data.DataRowVersion.Current, null));
this.oleDbUpdateCommand1.CommandText = @"UPDATE Customers SET CustomerID = ?,
CompanyName = ?, ContactName = ? WHERE (CustomerID = ?) AND (CompanyName = ?) AND
(ContactName = ? OR ? IS NULL AND ContactName IS NULL); SELECT CustomerID, CompanyName,
ContactName FROM Customers WHERE (CustomerID = ?)";
this.oleDbUpdateCommand1.Connection = this.oleDbConnection1;
this.oleDbUpdateCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("CustomerID", System.Data.OleDb.OleDbType.WChar, 5,
System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "CustomerID",
System.Data.DataRowVersion.Current, null));
this.oleDbUpdateCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("CompanyName", System.Data.OleDb.OleDbType.VarWChar, 40,
System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)),
"CompanyName", System.Data.DataRowVersion.Current, null));
this.oleDbUpdateCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("ContactName", System.Data.OleDb.OleDbType.VarWChar, 30,
System.Data.ParameterDirection.Input, true, ((System.Byte)(0)), ((System.Byte)(0)),
"ContactName", System.Data.DataRowVersion.Current, null));
this.oleDbUpdateCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("Original_CustomerID", System.Data.OleDb.OleDbType.WChar,
5, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)),
"CustomerID", System.Data.DataRowVersion.Original, null));
this.oleDbUpdateCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("Original_CompanyName",
System.Data.OleDb.OleDbType.VarWChar, 40, System.Data.ParameterDirection.Input, false,
((System.Byte)(0)), ((System.Byte)(0)), "CompanyName", System.Data.DataRowVersion.Original,
null));
this.oleDbUpdateCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("Original_ContactName",
System.Data.OleDb.OleDbType.VarWChar, 30, System.Data.ParameterDirection.Input, true,
((System.Byte)(0)), ((System.Byte)(0)), "ContactName", System.Data.DataRowVersion.Original,
null));
this.oleDbUpdateCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("Original_ContactName1",
System.Data.OleDb.OleDbType.VarWChar, 30, System.Data.ParameterDirection.Input, true,
((System.Byte)(0)), ((System.Byte)(0)), "ContactName", System.Data.DataRowVersion.Original,
null));
this.oleDbUpdateCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("Select_CustomerID", System.Data.OleDb.OleDbType.WChar, 5,
System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "CustomerID",
System.Data.DataRowVersion.Current, null));
this.oleDbDeleteCommand1.CommandText = "DELETE FROM Customers WHERE (CustomerID = ?) AND
(CompanyName = ?) AND"+ "(ContactName = ? OR ? IS NULL AND ContactName IS NULL)";
this.oleDbDeleteCommand1.Connection = this.oleDbConnection1;
this.oleDbDeleteCommand1.Parameters.Add(new System.Data.OleDb.OleDbParameter("CustomerID",
System.Data.OleDb.OleDbType.WChar, 5, System.Data.ParameterDirection.Input, false,
((System.Byte)(0)), ((System.Byte)(0)), "CustomerID", System.Data.DataRowVersion.Original, null));
this.oleDbDeleteCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("CompanyName", System.Data.OleDb.OleDbType.VarWChar, 40,
System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)),
"CompanyName", System.Data.DataRowVersion.Original, null));
this.oleDbDeleteCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("ContactName", System.Data.OleDb.OleDbType.VarWChar, 30,
System.Data.ParameterDirection.Input, true, ((System.Byte)(0)), ((System.Byte)(0)),
"ContactName", System.Data.DataRowVersion.Original, null));
this.oleDbDeleteCommand1.Parameters.Add(new
System.Data.OleDb.OleDbParameter("ContactName1", System.Data.OleDb.OleDbType.VarWChar, 30,
System.Data.ParameterDirection.Input, true, ((System.Byte)(0)), ((System.Byte)(0)),
"ContactName", System.Data.DataRowVersion.Original, null));
this.oleDbConnection1.ConnectionString = "Provider=SQLOLEDB.1;Persist Security Info=False;User
ID=sa;Initial Catalog=Northw" +
"ind;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Workstation" +
" ID=VMUKHI;Use Encryption for Data=False;Tag with column collation when possible" +
"=False";
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
}
 
The code for the function InitializeComponent has been inserted without us having to make
any changes at all. By now, you would have realized, as to why we are so fascinated with
Visual Studio.Net. It generates all the code required for a certain task, without a single error.
Let us spend a little time, trying to construe the above code. As there are six instance variables,
each of them will have a new statement, which will initialize them.
 
The first variable is of type OleDbDataAdapter class, which is used to fetch data from a
database. Then, we need SQL commands, which will help us in working with the records from
a table in the database. Thus, the 4 property statements of type OleDbCommand,
oleDbSelectCommand1, oleDbInsertCommand1, oleDbUpdateCommand1 and
oleDbDeleteCommand1, represent SQL statements, which are to be used while working with
records.
 
The columns in our table, require to be mapped to the columns in the data source. In order to
accomplish this, the TableMappings property of type DataTableMappingCollection, is employed.
This class contains a function called AddRange, which accepts an array of DataTableMapping
objects. A DataTableMapping class has a constructor, which accepts three parameters. The
first parameter is a string, which represents a Table. The second parameter is Customers,
which is the name of the table in the dataset, to map to. The third parameter is an array of
Column names.
 
The column names furnished in the last parameter are represented with the help of a
DataColumnMapping class. The constructor to this class is passed two parameters. The first is
the name of the column in the data source, while the second is the name of the column in the
dataset to map to. We have maintained both of these identical, although they could have
easily varied.
 
The SQL statement that we have written, generates this AddRange function. It associates or
maps the three chosen columns, with the columns in the Customers table. The
oleDbSelectCommand1 object requires an SQL select statement, which will determine the data
to be retrieved. The CommandText property is therefore, initialized to the Select statement
entered earlier in the Query Builder. The Connection property is initialized to the
OleDbConnection control, for each of the select, update, delete or insert objects.

For inserting data, the SQL statement has a? symbol, or a placeholder to hold text, which is to
be entered at run time. The syntax starts with the reserved word 'Insert into', followed by the
name of the table, followed by the field names, followed by the reserved word Values, and
finally, followed by a set of brackets, containing the actual data. This data can also be the
resultant data of a Select statement. Either of the three, i.e. ? or placeholder or parameter, is
filled with text supplied by the user at runtime. This is done for reasons of efficiency. The Insert
or Select statements are first parsed, and then, verified for various types of errors. This is a
protracted and time-consuming exercise. Therefore, the product of this action is stored for
reuse, thereby speeding things up. Thus, by the use parameters, execution can be speeded up,
since the database merely needs add the data, without checking the syntax. Three parameters
are to be added to the Insert object, since there are three column names, viz. CustomerID,
CompanyName and ContactName. The rules for adding a parameter remain the same, while
implementing all the three parameters.
 
The Parameters collection takes an OleDbParameter object, whose constructor accepts 10
parameters, which are as follows:
• The first parameter is the name of the parameter, and in our case, it is termed as
CustomerID.
• The second parameter is the data type of the parameter, which is of type OleDbType.
It may be any one of the numerous data types that are available. One such data type is
wchar, which is a series of Unicode characters, ending in a null. It maps to a string data
type in C#.
• The third parameter is the size or width of the column, which is 5 characters long.
• The fourth parameter, of type ParameterDirection, can contain only four values,
which specify whether the parameter is used for input or output; or both; or for the
return value of some code being executed on the server.
• The fifth parameter is a Boolean, which accepts a value of either True or False. In a
database, you can specify whether a field can contain a Null value or not. Null cannot
be equated to zero, since it specifically implies that the field is bereft of any value
whatsoever. A value of False necessitates the presence of a value in this field.
• The sixth parameter stands for 'precision', which indicates the exact number of
decimal places that a number can possibly have.
• The seventh parameter is the 'scale' parameter, which is also responsible for the
number of decimal places that the value can hold.
• The eighth parameter is the name of the source column in the table.
• The ninth parameter is of type DataRowVersion, and specifies the version of the
DataRow object being retrieved. The type Current represents the current or present
value. It can have three other values, viz. Default, Original and Proposed.
• The tenth parameter is Null. It stands for the value of any of the parameters. We may
use any data type, to assign a value to the parameter.
 
It would be so cumbersome if we had to write the above code by hand, for each of the
parameters in the Insert statement. This is surely a dreary job! Since someone has to do this
job, why not let the computer do it?
 
The 'update' command necessitates a similar treatment. So, we use the Update statement,
which starts with the reserved word Update, followed by the name of the table i.e. Customers,
and the 'set' keyword, which specifies the fields that need to be updated. There are three
placeholders or ? signs, since three fields have been chosen. The term 'where' is like a filter,
since in its absence, the update statement will update all records in the database. The eight
parameters that need to be annexed for the Update statement, are responsible for the
extremely lengthy code. The Delete statement is considerably more tractable than the code
specified above. It starts with the Delete keyword, followed by the name of the table, and a
'where' condition, which filters the number of records. The four placeholders require four
parameter statements.
 
Next comes the Connection object, oleDbConenction1. It is this particular object, which
understands how to aptly communicate with a database. The data that specifies how to
communicate with a database, is passed in the ConenctionString property. The Connection
string starts with the word 'provider', with the name of the database that we wish to talk to,
followed by a semi-colon, which acts as a separator. Then, we have the User ID of 'sa', since 'sa'
was entered in the dialog box. Next, we have the Catalog as the name of the database,
NorthWind. We shall explore the others, a little later.
 
The visible controls get added to the Forms collection, whereas the invisible controls do not.
The only difference between a visible control and an invisible control is that, the former shows
up in the form, while the latter shows up at the bottom. These concepts are divulged only after
the code that is generated, has been deciphered thoroughly. Otherwise, we shall just be
groping in the dark. Thus, we endeavor to understand the code from the absolutely basic
fundamentals.
 
Next, we generate the Data Set object, using the menu option Data- Generate Dataset, and we
name the Datatset as 'ddd'. The screen 6.5 represents the dataset dialog box.
 
Screen 6.5
 
Once this is done, switch to the Code Painter to view the new sets of commands. An instance
variable, called ddd1, gets created with the data type of z10.ddd. This is because, we named
our DataSet as 'ddd', and the dataset object in Visual Studio.Net was named 'ddd1'.
 
The next thing that we need to do is, to discover where the class ddd has been created. It does
not show up in the current file. We plan to unveil this class mystery, in just a short while.
 
But for now, we will take a look at the code of the dataset, which was created in the function
InitializeComponent.
 
private z10.ddd ddd1;
private void InitializeComponent ()
{
this.ddd1 = new z10.ddd();
((System.ComponentModel.ISupportInitialize)(this.ddd1)).BeginInit();
this.ddd1.DataSetName = "ddd";
this.ddd1.Locale = new System.Globalization.CultureInfo("en-US");
this.ddd1.Namespace = "http://www.tempuri.org/ddd.xsd";
}
 
As always, a new instance is created, and thereafter, a function called BeginInit is called. This
function is present in the interface IsupportInitialize, which explains the use of the cast
operator. This function merely enlightens the whole world with the news, that the object is
about to initialize itself. Unless the program reaches the EndInit function, initialization will not
be completed.
This is akin to fixing a 'Do Not Disturb' sign outside your door. The cast that we have above, is
really unnecessary, since the DataSet class implements the interface. Whenever computer
programs write code, they are extremely specific. The DataSetName is set to 'ddd', since we
opted for this name in the dialog box, during the creation of the dataset. The Locale property is
used to compare strings present in the table. The Namespace property is set to the name of an
xsd file. File ddd.xsd is shown below.
 
ddd.xsd
<xsd:schema id="ddd" targetNamespace="http://www.tempuri.org/ddd.xsd"
xmlns="http://www.tempuri.org/ddd.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" attributeFormDefault="qualified"
elementFormDefault="qualified">
<xsd:element name="ddd" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="Customers">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="CustomerID" type="xsd:string" />
<xsd:element name="CompanyName" type="xsd:string" />
<xsd:element name="ContactName" type="xsd:string" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
<xsd:unique name="Constraint1" msdata:PrimaryKey="true">
<xsd:selector xpath=".//Customers" />
<xsd:field xpath="CustomerID" />
</xsd:unique>
</xsd:element>
</xsd:schema>
 
This file displays a large number of tags, which we shall explicate while discussing XML. The
line of code in which the table name Customers is stored, is the most significant one. Within
the tag sequence, the three field names are present along with their data types. There is also an
attribute called PrimaryKey, which specifies that the CustomerID field is unique. The above
program named Form1.cs, cannot be compiled at this stage, since it does not contain any code
for the ddd class. The only way out is, to create this class from the xsd file. So, we use the xsd
program for this purpose. We run it as follows:
 
C:\mukhi\z10>xsd /d /n:z10 ddd.xsd
 
Output
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 1.0.2914.16]
Copyright (C) Microsoft Corp. 1998-2001. All rights reserved.
Writing file 'C:\mukhi\z10\ddd.cs'.
The /d option creates a class named ddd, derived from DataSet. The /n option places all the
code in the namespace z10. Finally, a file called ddd.cs gets created, from which, we have
extracted the initial few lines. Remember that, none of this 10K sized code, has been written by
us.
 
namespace z10
{
public class ddd : System.Data.DataSet
{
 
Now that the class ddd is available, compile the Form program, using the command
 
>csc Form1.cs ddd.cs
 
The compiler can be passed as many C# program files as you desire. We are not out of the
woods yet, since we have to introduce a DataGrid, which shall display all the data.
 
The moment we incorporate a DataGrid object, an instance variable named dataGrid1 gets
created.
 
private System.Windows.Forms.DataGrid dataGrid1;
 
Double click on the datagrid and you will see the following code in the function
InitializeComponent
 
this.dataGrid1 = new System.Windows.Forms.DataGrid();
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).BeginInit();
this.dataGrid1.DataMember = "";
this.dataGrid1.Location = new System.Drawing.Point(56, 40);
this.dataGrid1.Name = "dataGrid1";
this.dataGrid1.TabIndex = 0;
this.dataGrid1.Navigate += new
System.Windows.Forms.NavigateEventHandler(this.dataGrid1_Navigate);
this.Controls.AddRange(new System.Windows.Forms.Control[] {this.dataGrid1});
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).EndInit();
 
private void dataGrid1_Navigate(object sender, System.Windows.Forms.NavigateEventArgs ne)
{
}
 
The Navigate event gets fired, whenever we move into a new table in the data grid, since the
DataMember property is blank by default. The whole world appears to be pre-occupied with
calling the BeginInit and EndInit functions. They all behave in a similar manner.
 
We finally set DataSource to ddd1 and DataMember to Customers. These are the two most
important properties in the Properties window.
this.dataGrid1.DataSource = this.ddd1;
this.dataGrid1.DataMember = "Customers";
 
The Fill function is placed in the Form1_Load function before running the program, as the
dataset needs to be filled up with data.
 
private void Form1_Load(object sender, System.EventArgs e)
{
oleDbDataAdapter1.Fill(ddd1);
}
 
The next application will selectively retrieve data from the customers table. To be precise, we
will provide a customer number, and instantly, specific details about that customer will be
displayed. But prior to this, we intend to display a single record from the customers table in
the textboxes.
 
Save all the files, and close the current Solution. Then, click on File - New - Project, and choose
Visual C# Project in the first pane and Windows Application in the second pane. Assign the
name z14 to the project, and locate it in C:\mukhi. Then, click on the OK button. Do ensure
that the Properties and the ToolBox windows are visible.
 
Click on the Data tab in the toolbox, and then usher-in the OleDbDataAdapter control. This
activates the wizard. On the first screen, simply click on the Next button. To obtain the name of
Data Connection, click on the drop down listbox, and select the one named Northwind
database. Then, click on the Next button, leaving the SQL statements selected; and then, write
the following SQL statement:
 
SELECT CustomerID, CompanyName, ContactName FROM Customers
 
Finally, click on the Finish button. The two invisible objects get created in the lower pane. We
are also aware of the fact that, great many lines of code have been generated.
 
Click on menu Data - Generate Dataset. Change the name of the dataset to ddd, and then,
click on OK. Thereafter, drag-and-drop three textboxes onto the form, from the ToolBox in the
Windows Form tag.
 
Select the first textbox, and in the Properties Window, click on the plus sign in front of
DataBindings. This will bring up the DataBindings options. Click on the drop down listbox for
the property Text. This will reveal the dataset ddd1, with a plus sign in front of it. A dataset
contains a large number of tables. Hence, we see a plus sign along with it, in the Properties
Window. Click on the plus sign with ddd, to display a list of tables present in it. Since there is
only one table present, we see only the Customers table listed, but with a plus sign. Every table
contains columns. Clicking on the plus sign, will display the three column names contained in
customers. Select CustomerID, as shown in screen 6.6.
 

Screen 6.6
 
By selecting the column CustomerID for the first textbox, we confine the display of all values
related to CustomerID, to this particular textbox alone. Follow the same procedure to select
CompanyName for the second textbox, and finally, to select ContactName for the third textbox.
After effecting this, double click on the form, to enter the Fill function in the function
Form1_Load.
 
oleDbDataAdapter1.Fill(ddd1);
 
Then, press F5 to run the application.
 
Screen 6.7
 
In screen 6.7, the three fields of the first record are displayed in the three textboxes.
 
Let us now introduce a button from the Windows Form tab so that the record pointer moves to
the next record when clicked on the button. Change the text property in the Properties window
to Next, and then, double click on the button. You will be transported to the function
button1_Click. Now, enter the following line of code:
 
BindingContext[ddd1, "Customers"].Position += 1;
 
The Form class has a property called BindingContext, of data type BindingContext. This
property, in turn, has an Indexer that accepts two parameters. As was explained in the
previous chapter, an Indexer looks like an array, walks like an array and talks like an array;
but it is not an array!
 
The two parameters that this Indexer accepts are:
• The name of the dataset, i.e. ddd1.
• The name of the table, which is within that DataSet, i.e. Customers.
 
This indexer returns a BindingManagerBase object, which has a property called Position. This
property contains the current record pointer.
 
The record pointer or active record, is an abstract entity, which marks a single row of data in
the dataset that becomes visible to everyone. The value contained in the Position property
activates the specific row in the dataset. The initial value starts at zero.
 
Each time we click on the button, the value is incremented by 1, using the += syntax.
 
Screen 6.8
 
The above code can be re-written effortlessly, as follows:
 
BindingManagerBase a;
a= BindingContext[ddd1, "Customers"];
a.Position = a.Position + 1;
 
This code is a simplified version of the earlier one. However, it is infested with a small bug. If
the value of the Position parameter exceeds the number of records, no error is generated. In
such a situation, the last record will be displayed. So, how do we redress this problem?
 
Introduce another button, and change the Text property to Prev. Then, double click on this
button, and in the Code Generator for the function button2_Click, add the following line of
code.
 
BindingContext[ddd1, "Customers"].Position -= 1;
 
Now, on running the application, two buttons will be visible, as shown in screen 6.9.
 
Screen 6.9
 
Each time we click on the Next button, the record pointer moves to the next record; whereas,
every time we click on the Prev button, it moves to the previous record.
 
Thus, each and every record can be accessed sequentially, in the forwards or backwards
direction.
 
Now, we add one more button, which moves the record pointer directly to the first record.
Change its text to 'First', and then, double click on it, to add the following line of code:
 
BindingContext[ddd1, "Customers"].Position = 0;
 
Once this is done, build the project, and press F5 to run the program. Click on the Next button
a couple of times, and then, click on the button labeled First. On doing so, the record pointer
jumps directly to the first record, and it gets displayed. This occurs on account of the fact that,
when the Position property is set to zero, the first row in the dataset becomes the active row.
Finally, select a button in the Toolbox, and change its Text property to Last. Then, add the
following lines of code to it:
 
int i;
i = BindingContext[ddd1, "Customers"].Count;
BindingContext[ddd1, "Customers"].Position = i-1;
 
The BindingManagerBase class has a member called Count, which provides the total count of
rows or record sets available in the dataset. The variable i is set to the value of this property.
Then, the Position parameter is initialized to one less than the value of i, since the index of the
Position parameter begins with a value of zero. Thus, if we have 10 rows, the value of the count
property will be 10. The index value of the first record will be 0, and that of the last record will
be 9.
 
There is yet another feature remaining, which is a textbox that reveals the current position, or
the current record number, in the dataset. Each time the Position property changes, the new
record number must be displayed. In fact, the position changes whenever any button is
clicked. The code required to display the new record numbers, remains unchanged. So,
instead of repeating the same code four times, once for each of the four different buttons, we
shall enclose this code within a function. This function will then be called by each of the four
buttons.
 
So, select the textbox from the Toolbox window. The textbox will be named textBox4.
 
Then, enter the function abc, as shown below, after the last function. The four buttons shall
now call this function.
 
Screen 6.10
 
void abc()
{
int cnt,pos;
cnt = BindingContext[ddd1, "Customers"].Count;
pos = BindingContext[ddd1, "Customers"].Position;
pos = pos+1;
textBox4.Text = "Record No " + pos + " of Record " + cnt;
}
 
Also, call the abc function after the Fill function in Form_Load.
 
private void Form1_Load(object sender, System.EventArgs e)
{
oleDbDataAdapter1.Fill(ddd1);
abc();
}
 
In the function abc, we initialize the variables 'cnt' and 'pos' to the total number of rows and
current record position, respectively. The 'pos' variable must be increased by one, since the
index is zero-based, i.e. it starts at zero.
 
The Text property of the textbox named textBox4, is initialized to the new values. The strings
are placed within double quotes, whereas, the integers are automatically converted to strings,
so that no extra effort is required on our part. The plus sign is employed to join two strings,
and is known as the 'string concatenation operator'.
 
Screen 6.11
 
There are numerous records in the dataset. So, we shall now essay towards displaying only
those records that meet certain criteria. To do so, select the OleDbDataAdapter object in the
form, and then, for the property SelectCommand, click on the 'plus' sign, to view the Dynamic
properties.
 
When the button for the property CommandText having 3 dots is clicked, it displays the screen
as reflected below.
 

Screen 6.12
 
Here, we notice the same screen that was displayed in the wizard. The SQL statement is
modified to the following:
 
SELECT CustomerID, CompanyName, ContactName FROM Customers WHERE City = ?
 
Addition of the WHERE clause results in the display of customers belonging to a specific city
only. The name of the city will be provided by the user, during program execution. The ? sign is
a parameter or placeholder, which accommodates the name of the city.
 
Before building and running the application, introduce a textbox and a button.
 
Change the Text property of the button to 'Show', and then, double click on the button to enter
the following lines of code:
 
oleDbDataAdapter1.SelectCommand.Parameters["city"].Value = textBox5.Text;
ddd1.Clear();
oleDbDataAdapter1.Fill(ddd1);
abc();
 
There is just one more assignment to complete, before we wind up. Empty the function
Form1_Load. Now, run the program, and in the newly inserted textbox, enter 'London'. Then,
click on the Show button. The output reveals that the city of London has six customers. Screen
6.13 provides the proof.
 

Screen 6.13
 
Now, if you change 'London' to 'Paris', you will see only two customers from this city. Thus,
from amongst the 91 customers, we can selectively view only those who belong to a certain city.
 
Now let us try to appreciate the 'behind the scene' activities.
 
The SelectCommand property in the oleDbDataAdapter, has a property named Parameters. It is
actually an indexer that requires a string parameter to reference the parameter 'name'. The
Value property of the indexer is initialized to the city name provided in the Text property of the
textBox5. It is indeed a good idea to clear the dataset of all records, using the clear function.
Then, the same Fill function is called, followed by the abc function. Thus, the presence of
parameters makes our program extremely generic. The above code can be re-written in a
simple format, as shown below.
 
System.Data.OleDb.OleDbCommand a;
a= oleDbDataAdapter1.SelectCommand;
System.Data.OleDb.OleDbParameterCollection p;
p = a.Parameters;
System.Data.OleDb.OleDbParameter p1;
p1 = p["city"];
p1.Value = textBox5.Text;
ddd1.Clear();
oleDbDataAdapter1.Fill(ddd1);
abc();
 
The property SelectCommand is of data type OleDbCommand. It belongs to the
System.Data.OleDb namespace. If the 'using' clause is not provided for this namespace, we
have to write the entire name of the namespace. This can be avoided by employing the 'using'
keyword. The OleDbCommand has a property named Parameters, which is of data type
OleDbParameterCollection. This property, in turn, has an indexer that takes the parameter
name as a string parameter, and returns an OleDbParameter. The Value member of this object
p1, is initialized to the Text property of the textbox.
 
Finally, you can change the Text property of all the textboxes to empty strings, because the
initial display lacks in aesthetic appeal. There are no bounds to the number of enhancements
that we can effect to the above program.
The presence of four copies of the function abc, one for each of the above four click functions,
also does not appeal to us. So, we eliminate the calls to the function abc from the four click
functions, and add the following code to the click function of button5:
 
BindingManagerBase z;
z= BindingContext[ddd1, "Customers"];
z.PositionChanged += new EventHandler(abc);
 
Also, the abc function requires to be amended, to read as follows:
 
void abc( object s, System.EventArgs e)
 
The BindingManagerBase object z is first initialized, and then, the PositionChanged delegate is
assigned to the function abc. Thus, each time the Position property changes, the abc function
gets called. There is no need for us to call the abc function explicitly, since the system calls it,
whenever there is a change in the Position property.
 
Every Windows Application comprises of a menu. So, how do we place menus in our Windows
Application? As is generally done, we shall examine this process, one step at a time. We shall
also display the code generated by Visual Studio.Net, so that you are able to grasp the concept
of Menu Handling in C#.
 
As always, save all the files, and start with a new project, using the File - New - Project menu
option. In the dialog box, select the Project type as Visual C# Project, and in the Template
pane, select the template as Windows Application. Name the project as s2, and locate it at
c:\mukhi. Then, click on OK. You also need to ensure that the Properties and the Toolbox
windows are visible. From the ToolBox, under the Windows From tab, select the MainMenu
control and drag-and-drop it into the Form. We merely witness a message Type Here. This is
shown in screen 6.14. When we insert the word File, the menu changes to the one shown in
screen 6.15.
 
Screen 6.14 Screen 6.15
 
On building and running the program, the screen displays the word File, as shown in screen
6.16.
 

Screen 6.16
 
On clicking this menu item, nothing gets displayed, and in effect, nothing transpires. We now
go back to the Code Generator, and have a look at the code that is generated.
 
private System.Windows.Forms.MainMenu mainMenu1;
private System.Windows.Forms.MenuItem menuItem1;
 
There are two instance variables, mainMenu1 of data type MainMenu, and menuItem1 of data
type MenuItem.
 
If you click on the word File in the Design Mode, the properties window will display the
properties for this menu item object. This is shown in screen 6.17.
 
Screen 6.17
 
private void InitializeComponent()
{
this.mainMenu1 = new System.Windows.Forms.MainMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuItem1});
this.menuItem1.Index = 0;
this.menuItem1.Text = "File";
this.Menu = this.mainMenu1;
}
 
The function InitializeComponent contains the entire menu-generated code. Here, we first
create an instance for the two menu objects. The mainMenu1 object has the MenuItems
property, which in turn, calls the AddRange function. This function adds an array of MenuItem
objects. As we are in possession of only one such object, the array displays this solitary object
named menuItem1. This procedure is similar to the one used earlier for adding controls to the
Form.
 
The Index property shows 0, since it is the first menu item. The text property displays File. The
Form class has a property called Menu, which is initialized to the object MainMenu1. This
main menu object knows all about the other menu items that are to be displayed.
 
To add another menu item, click on the word File. This will open up an additional box on the
right. Enter the text 'Edit', as shown in screen 6.18.
 
Screen 6.18 Screen 6.19
 
Build and run the application. A screen is displayed, containing two menu items named File
and Edit, as is clearly seen in screen 6.19.
 
With the introduction of one more menu item, the default name assigned to it becomes
menuItem2. An instance variable of the same name is created in the code file.
 
private System.Windows.Forms.MenuItem menuItem2;
 
private void InitializeComponent()
{
this.menuItem2 = new System.Windows.Forms.MenuItem();
this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuItem1, this.menuItem2});
this.menuItem2.Index = 1;
this.menuItem2.Text = "Edit";
}
 
In the InitializeComponent function, additional code gets added for the second menu item. The
object menuItem2 is first initialized and then, it is added to the array, which is to be provided
to the AddRange function. We would have had to add them individually, if the array did not
exist. Thus, adding 10 menu items would have entailed calling the function 10 times.
 
The index property for this menu item is shown as 1, since it is the second menu item. The text
property shows the newly entered text as Edit.
 
Now, we shall add an item to the File menu. Click on the word File, and enter the word New, as
displayed in screen 6.20.
 
Screen 6.20 Screen 6.21
 
Then, build and run the application. Click on the File menu, and it will display a popup menu,
containing the word New. This is presented in screen 6.21.
 
Let us now look at the code, which generates the popup menu.
 
private System.Windows.Forms.MenuItem menuItem3;
 
private void InitializeComponent()
{
this.menuItem3 = new System.Windows.Forms.MenuItem();
this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {this.menuItem1,
this.menuItem2});
this.menuItem1.Index = 0;
this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuItem3});
this.menuItem1.Text = "File";
this.menuItem3.Index = 0;
this.menuItem3.Text = "New";
}
 
In order to store the word New, one more MenuItem named menuItem3, gets added. A new
instance is also created for this purpose. This menu item is not added to the array provided in
the AddRange function of mainMenu1.MenuItems. However, the menuItem1 object has a
similar property named MenuItems, which has an AddRange function. This function also
accepts an array of MenuItems.
 
Since only a single MenuItem named New is to be added, this array holds only one member.
The Index property of menuItem3 is assigned a value of zero, since it is the first menu item
under File.
 
Similarly, if we add one more item named Open just below New, another variable named
menuItem4 will be created, and the Addrange function will now read as follows:
 
this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuItem3,this.menuItem4});
 
Thus, there will be two menu item objects in the array, which will be passed to the AddRange
function of the menuItem1 object. Now, each time that the menu item Open is clicked, we
desire that some specific code should be called. Click on the left side of the word Open, with
the left mouse button. You will arrive at the screen shown in 6.22. Here, we see a tick-mark on
the menu.
 

Screen 6.22 Screen 6.23


 
Build and run the program. Now, click on the File menu. You will see the tick-mark displayed
on the menu item Open. This is shown in screen 6.23.
 
The tick-mark indicates that the menu has already been checked. This exists primarily for the
purpose of reminding the user that the menu had been selected earlier.
 
this.menuItem4.Checked = true;
this.menuItem4.Index = 1;
this.menuItem4.Text = "Open";
 
The MenuItem Open is called menuItem4, and has a property called Checked. This property
when set to True, merely checks the menu.
 
Now, we desire that each time we click on the Open menu, the menu labeled New should get
disabled. To make this happen, double click on the word Open and enter the following code in
the Code Painter.
 
private void menuItem4_Click(object sender, System.EventArgs e)
{
menuItem3.Enabled = false;
}
 
The above function gets called only because the Click event of the menu item object
menuItem4, has been set to the function MenuItem4_Click. As before, the name of the object is
followed by the underscore sign, and then, by the magic word Click. The above function
disables the menu item labeled New or menuItem3.
 
Build and run the program. Then, Click on File - Open. On doing so, the above function gets
called; thus disabling the New option. Therefore, you are in complete control of the code that is
to be executed, when the menu option is clicked.
 

Screen 6.24
 
Save all the files and create a new project. In the dialog box, select the project type as Visual
C# Project, and the Template as a Windows Application. Name the project as s3, and locate it
at c:\mukhi. Then, click on OK. As before, the Properties Window and the Toolbox must be
activated. Move down the scroll bar in the toolbox, and select the control ContextMenu. Drag-
and-drop it into the form.
 
Screen 6.25 shows the screen that encompasses the introduction of the ContextMenu.
 

Screen 6.25
 
The generated code contains the instance variable contextMenu1, of data type ContextMenu.
 
private System.Windows.Forms.ContextMenu contextMenu1;
 
private void InitializeComponent ()
{
this.contextMenu1 = new System.Windows.Forms.ContextMenu();
}
 
Also, in the function InitializeComponent, the instance variable contextMenu1 is initialized to a
ContextMenu object. No additional code is required, since a ContextMenu is always added to a
control. Clicking with the right mouse button on the control, displays this menu. Hence, it is
termed as a ContextMenu.
 
Now, we shall add two menu items to this Context Menu. Make sure that the Context Menu
object is highlighted at the bottom of the screen. Then, click on the words ContextMenu, as
exhibited in screen 6.26.
 

Screen 6.26
 
Replace the words 'Type Here' with the word 'New'. Then, click on the words 'Type Here' given
below, and replace it with 'Open'.
 
Thus, we now obtain two menu items in the context menu. But, the moment we click on the
Form, the context menu disappears, since it is required to be displayed only when the context
menu control is selected. This is unlike a main menu object. The extra code that is required for
adding the items to a context menu, is as follows:
 
private System.Windows.Forms.MenuItem menuItem1;
private System.Windows.Forms.MenuItem menuItem2;
 
private void InitializeComponent ()
{
this.menuItem1 = new System.Windows.Forms.MenuItem();
this.menuItem2 = new System.Windows.Forms.MenuItem();
this.contextMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuItem1,this.menuItem2});
this.menuItem1.Index = 0;
this.menuItem1.Text = "New";
this.menuItem2.Index = 1;
this.menuItem2.Text = "Open";
}
 
For the two menu items New and Open, there exist two instance variables, menuItem1 and
menuItem2. In the function InitializeComponent, the two menu item objects are initialized;
then, the AddRange function is used, which is present in the MenuItems collection property of
the context menu object contextMenu1. The array passed to this function contains the two
menu items as its members. Thus, a context menu is no different from any other menu.
 
Let us return back to the Design Mode and incorporate a button and a textbox in the Form.
Select the button, and in the Properties Window, move to the property called ContextMenu.
Click on the drop down listbox to arrive at a list of context menus, which are currently
available for the Form. Since only one contextmenu1 is present, a solitary option is revealed.
Select this option. Then, choose the textbox, and in the drop down listbox of the property
ContextMenu, pick the context menu named contextMenu1.
 
On having done so, nothing earth-shattering occurs. If you cast a glance at the code, you will
notice that the property ContextMenu of the Textbox, and that of the Button, has been
initialized to contextmenu1. Press F5 to run the program, and then, right click with the mouse
on the Button. And there you go! The menu is now visible on the screen, containing two items,
viz. New and Open. This is shown in screen 6.27.
 

Screen 6.27
 
We now incorporate a few amendments to the application, by adding a few more menu items to
the context menu. We also activate a function, when the control associated with the context
menu is clicked.
 
To do so, add the following line of code to the InitializeComponent function:
 
this.contextMenu1.Popup += new System.EventHandler(abc);
 
The ContextMenu class has an event called Popup, which is associated with the function abc.
This event gets triggered, whenever we click on the right mouse button. It is a good practice to
place similar code together. This is merely a suggestion. Accordingly, we have placed all code
related to the ContextMenu together.
 
We have placed the above code immediately after the AddRange function. The exact location
does not matter, as long as it is placed inside the function, and is located after an instance has
been created.
 
We also need to create the function abc, and call the Show function in it. The code specified
below is placed after the Main function.
 
private void abc(object sender, System.EventArgs e)
{
MessageBox.Show("hi");
}
 
Press F5 to run the program, and then, click with the right mouse button. Before the popup
springs up, we notice a Message Box, as shown in screen 6.28.
 

Screen 6.28 Screen 6.29


 
Close the application. Select the context menu and double click on the menu item Open. In the
function menuItem2_Click, call the MessageBox.Show function, as demonstrated below.
 
private void menuItem2_Click(object sender, System.EventArgs e)
{
MessageBox.Show("bye");
}
 
This function gets called, because the Click event of the menuItem2 has been added to our
code as follows:
 
this.menuItem2.Click += new System.EventHandler(this.menuItem2_Click);
 
Build and run the program. Then, click on either the button or the textbox, with the right
mouse button. We first click on the Message Box displaying "hi", and then, on the Open menu
item in the popup. This will bring up the Message Box displaying "bye". Thus, a menu item
located in a popup behaves akin to an ordinary menu.
 
When we click on the popup, we desire to add one more menu item. So, all that we need to do
is, add the following line of code in the function abc:
 
contextMenu1.MenuItems.Add("mukhi");
 
The Add function in the MenuItems will add a menu with the text mukhi. Remove the Show
function, since it is of no use at all.
 
Now, build and run the application, and then right click on the button. The menu that pops
up, contains the menu item of "mukhi". Then, right click on the textbox. This will display the
menu item "mukhi" twice.
 

Screen 6.30 Screen 6.31


 
We want to make a slight modification here. We intend that the menu item be added only when
the button is selected. We also want specific code to be called. To achieve this, make the
following changes in the function abc:
 
private void abc(object sender, System.EventArgs e)
{
contextMenu1.MenuItems.Add("mukhi");
if ( ActiveControl is Button)
contextMenu1.MenuItems.Add("sonal",new System.EventHandler(pqr));
}
 
The 'if' statement makes use of the property ActiveControl, which belongs to the Form class.
This is a dynamic property of data type Control. It contains the currently active control or the
control that has 'focus'. If it happens to be a Button, the 'if' statement evaluates to True. The
term 'is' is a keyword in the C# programming language. It has a literal meaning, just as in
English. Thus, we use the Add function of the MenuItems collection, to add a menu called
'sonal'. This is the first parameter, and the Eventhandler is the second parameter, representing
a function named pqr.
 
private void pqr(object sender, System.EventArgs e)
{
MessageBox.Show("end");
}
 
The pqr function merely displays a Message Box.
 
On running the application, we see the button already selected as it is the first control on the
form, or more precisely has the tab index of 0. A selected button adds sonal to the list of
menuoptions, so right clicking on any of the control will display sonal along with mukhi.
 
Click on the textbox to select the textbox control. As the button looses focus, the if statement
with the ActiveControl property check on Button results in false. As a result, sonal is not
added again to the menu options. This can be verified by right clicking on any control. Clicking
on 'sonal' will display a MessageBox, containing the text "end".
 

Screen 6.32 Screen 6.33


 
Thus, we can change the state of any property that we desire, since we have access to the
menu objects.
 
Now, save all the files, and start afresh with a new project. Name the C# Windows Application
as s4, and select the location as c:\mukhi. Then, click on OK. The Properties window and the
Toolbox should be visible.
 
Now, incorporate the MainMenu control, and for the first menu item, enter "Vijay", and for the
one below it, enter "Mukhi". The screen 6.34 displays these two menu items.
 

Screen 6.34
 
Now, usher-in another MainMenu object on the form, and for the first menu item, assign the
text "Sonal", and for the one below it, enter "File". The screen 6.35 displays the outcome of
these actions.
 

Screen 6.35
 
We may acquire as many MainMenu objects as desired, but only one of them will be active at
any given time. So, the form will initially show the first mainMenu1 to be active. The second
menu object mainMenu2 will become visible, only when it is clicked on, in the bottom frame.
 
Now introduce two buttons into the Form.
 
Change the Text property of the first button to 'First', and then, double click on the button. In
the function button1_Click, enter the following code:
 
Menu = mainMenu1;
 
Similarly, change the Text property of the second button to 'Second', and double click on the
button, to enter the following line of code:
 
Menu = mainMenu2;
 
Once this is achieved, build and run the program. The first menu called "vijay", will be visible
by default. Clicking on the button labeled "Second", will immediately result in a switch to
"Sonal". This is shown in screen 6.36.
 
Screen 6.36
 
Clicking on the button labeled "First", will again revert the menu back to the original, i.e. to
"Vijay".
 
Thus, we are empowered to change the main menu at any given time. We are also permitted to
have as many menu objects as we like. Further, we can point the Menu property to any Menu
object that we desire. Thus, at startup, a user sees a solitary menu, and after accomplishing
certain tasks, the menu switches to a more complex layout.
 
Thus, you may have realized by now, that it is much more productive to work with a Menu
Painter, than to manually write lines of tedious code.

You might also like