Microsoft Cloud Authors: Andreas Grabner, Nick Basinger, Kevin Benedict, Pat Romanski, Liz McMillan

Related Topics: Microsoft Cloud

Microsoft Cloud: Article

C# and the .NET Framework: Tying It All Together

Part 2: Adding menu bars, event handlers, and application logic

This is the second in a series of articles that build an application using C# and the .NET Framework. Our model application is the Windows Notepad.

What We've Done
In the first article (.NETDJ, Vol. 2, issue 1), we built the framework of our application as follows:

  • We built the NetpadForm class - a Windows Form class that will ultimately encompass most of the functionality of Netpad.
  • We added a TextBox object to the form to provide our text editing interface.
  • We added a menu bar, the File menu, and the File/Exit menu item to the form, and added an event handler to the File/Exit menu item.
Where We're Going
In this article, we're going expand Netpad by adding clipboard commands (Undo, Cut, Copy, Paste, Delete, and Select All), an Insert Time/Date command, and a Word Wrap command. These commands will be added to two new top-level menus, Edit and Format.

Creating the Edit and Format Menus
Most of our commands - all the clipboard commands and the Insert Time/Date command - will be included in the Edit menu. The top-level Edit menu and each menu item below it will be instances of the MenuItem class (from the System.Windows.Forms namespace). The main menu itself, which we created in the first article (and stored in the property _mainMenu), is an instance of the MainMenu class (also from the System.Windows.Forms namespace).

To create our Edit menu, we're going to do things a little different than before. In the first article, we created a MenuItem object for the File menu, and then added it to the menu bar:

_miFile = new MenuItem( "&File" );
_mainMenu.MenuItems.Add( _miFile );

We are going to shorten these two commands into one by taking advantage of a .NET feature called method overloading. Method overloading allows a method to do different things depending on what parameters are passed to it.

Look at the code below, which does the same thing as the code above:

_miFile = _mainMenu.MenuItems.Add( "&File" );

The key difference is in the Add method:

  • In the first code block, we created the MenuItem, _miFile, and then added it to our main menu, _mainMenu, using the Add() method.
  • In the second code block, we do not create the MenuItem object directly. Rather, by passing a string - "&File" - to the Add() method, the method creates the new MenuItem object for us and adds it to the menu.
The second code block allows us to save a line of code by allowing the Add() method to do some extra work for us. Convenient? Yes. Necessary? No. Neither way is right or wrong. Some feel that using method overloading makes code more readable or less readable. Use the technique you are most comfortable with.

Here's how we create our Edit menu:

_miEdit = _mainMenu.MenuItems.Add( "&Edit" );

For the commands under the Edit menu, we will employ two more techniques. First, we need to add a shortcut key to each menu item, ensuring we can undo by pressing Ctrl-Z, cut by pressing Ctrl-X, and so forth. To set a shortcut key, we will set a value to the Shortcut property of the menu item. See how we create the Undo menu item below:

_miEditUndo = _miEdit.MenuItems.Add( "&Undo" );
_miEditUndo.Shortcut = Shortcut.CtrlZ;

Next, below the Undo option, we want a horizontal line as a spacer. This is actually another MenuItem object, created by naming your item with a single hyphen, as shown below:

_miEdit.MenuItems.Add( "-" );

The rest of the code to create our Edit menu follows. Note the use of the function key shortcut for the Time/Date menu item.

_miEditCut = _miEdit.MenuItems.Add( "Cu&t" );
_miEditCut.Shortcut = Shortcut.CtrlX;
_miEditCopy = _miEdit.MenuItems.Add( "&Copy" );
_miEditCopy.Shortcut = Shortcut.CtrlC;
_miEditPaste = _miEdit.MenuItems.Add( "&Paste" );
_miEditPaste.Shortcut = Shortcut.CtrlV;
_miEditDelete = _miEdit.MenuItems.Add( "&Delete" );
_miEditDelete.Shortcut = Shortcut.Del;
_miEdit.MenuItems.Add( "-" );
_miEditSelectAll = _miEdit.MenuItems.Add( "Select &All" );
_miEditSelectAll.Shortcut = Shortcut.CtrlA;
_miEditTimeDate = _miEdit.MenuItems.Add( "Time/&Date" );
_miEditTimeDate.Shortcut = Shortcut.F5;

The Format menu is created the same way. See the final Netpad source code for this article to see the details.

Menu Events and Event Handlers
Now that we created our menu items, we need to make them do something. To do this, we will use event handlers.

Most objects in .NET can respond to events. Some events are driven by the user interface, such as mouse clicks and keystrokes. Others are driven by application logic, such as objects being created and destroyed.

An event handler is a method that is called upon an event occurring. When the event occurs, the event handler method is called. The event handler method is passed two parameters that define the sender (the object which created the event) and the event arguments (information that describes what's happening in the event). The process of connecting an event handler method to a particular object's event is often called wiring.

The best way to learn this is by example. I'll show you how to write the event handler method for the clipboard menu items in the Edit menu: Undo, Cut, Copy, Paste, and Delete.

Writing the Clipboard Event Handler Methods
Look at the method below, which is the event handler for the Undo menu item. Note that we named it MenuEditUndo_Click because the name is clear and descriptive: it's a method to respond to the Click event for the Undo menu item in the Edit Menu.

protected void MenuEditUndo_Click( System.Object sender, System.EventArgs e )
	// Call the textbox's Undo method

All event handler methods accept two parameters. The first parameter (sender) is a reference to the object that sent the event. In this example, it is the MenuItem object for the Undo menu item, _miEditUndo. The second parameter is a reference to an event arguments object. This object can contain specific data about the event, and can vary greatly depending on the sender. Menu item clicks generate event data that can be much different than other events. For specific details, you will need to review the .NET Framework documentation. But for now, you don't need to be concerned with this.

The method itself does one thing: it calls the Undo() method of the _textBox object. The _textBox object is an instance of the System.Windows.Forms. TextBox class, and it provides the functionality for the "notepad" part of Netpad - the area where we type and edit our text. Part of the functionality of all TextBox objects is clipboard methods: Undo(), Cut(), Copy(), and Paste(). We'll use each of these for our Undo, Cut, Copy, and Paste menu items.

What about the Delete menu item? Consider what this menu item does: it deletes the currently selected (highlighted) text. Implementing this is easy, as the TextBox class provides a SelectedText property. To clear the selected text, just set this property to an empty string, as shown below:

__textBox.SelectedText = "";

Connecting the Clipboard Event Handler Methods
Now that we have our event handler method, we can connect it to the _miEditUndo object. Here's the code for doing this:

_miEditUndo.Click += new EventHandler( MenuEditUndo_Click );

To see how this works, read it as follows:

Add (+=) a new EventHandler object, MenuEditUndo_Click,
to the Click property of the _miEditUndo object.

That's all there is to it. The rest of the clipboard event handler methods are connected as follows:

_miEditCut.Click += new EventHandler( MenuEditCut_Click );
_miEditCopy.Click += new EventHandler( MenuEditCopy_Click );
_miEditPaste.Click += new EventHandler( MenuEditPaste_Click );
_miEditDelete.Click += new EventHandler( MenuEditDelete_Click );

As you can see, it's the same process each time. The ease of programming with events in .NET and C# is one of its best features. I won't illustrate here the code to connect the remaining event handlers, as it's the same process over and over again.

The Select All Menu Item
The Select All menu item will select all the text in the text box - the equivalent of highlighting all the text with the mouse. To do this, we need to take advantage of three properties of the TextBox class:

  1. SelectionStart identifies the starting point of selected text in the text box, with the first character being zero.
  2. SelectionLength identifies the length of the selection string, in characters.
  3. Text identifies a string that returns the current content of the entire text box.
To select all the text in the text box, we will set the SelectionStart property to zero (the beginning of the text box), and set the SelectionLength to equal the length of Text (that is, the length all the text in the text box). The code below accomplishes this, and is the code that will be placed in the event handler method for the Select All command:

_textBox.SelectionStart = 0;
_textBox.SelectionLength = _textBox.Text.Length;

The Time/Date Menu Item
The Time/Date menu item inserts the current time and date into the text box. If there's a block of text that is selected, the time/date replaces this text. Otherwise, it's inserted at the insert point. All the code that follows will become part of the Insert Time/Date event handler method.

To start, we need to identify the time and date. We do that as follows:

string timeDate;
timeDate = DateTime.Now.ToShortTimeString() + " " +

DateTime is an object that provides us with date and time functions. ToShortTimeString() and ToShortDateString() return the time and date formatted as appropriate for the localization (country) settings on his PC. In other words, in the United States the date February 12 2004 will format as 2/12/2004; in the United Kingdom, it will format as 12/02/2004.

Next, we have to determine where we insert this string - either at the insert point, or by replacing the current selected text. Using the SelectedText property discussed previously, we can tell if there is any text selected: if the length of SelectedText is zero, then we know nothing is selected:

if ( _textBox.SelectedText.Length == 0 )

If there is text selected, inserting the timeDate string is easy. Just set the SelectedText property to timeDate. The end result is that the selected text (SelectedText) is changed to be equal to timeDate:

_textBox.SelectedText = timeDate;

If there is no text selected, we need to do a bit more. We not only need to insert the timeDate string at the current insert point (the current insert point is determined by the SelectionStart property), we also need to move the current insert point so it's directly after the time and date string we insert, as if the user typed the information themselves.

To do this will take three steps:

Step 1: Store the new insert point as the current insert point plus the length of the time/date string.

int newSelectionStart = _textBox.SelectionStart + timeDate.Length;

Step 2: Add the time/date string to our TextBox control. To do this, we use the Insert() method, which inserts a given string (timeDate) at a given point (SelectionStart) in a string.

_textBox.Text = _textBox.Text.Insert( _textBox.SelectionStart, timeDate );

Step 3: Update the insert point of our TextBox control to the insert point stored in Step 1.

_textBox.SelectionStart = newSelectionStart;

The WordWrap Menu Item
Our last item is the Word Wrap command in the Format menu. Fortunately, this is a simple task, since the TextBox object has word wrap functionality built in. To turn word wrapping on or off, we will set the WordWrap property of our TextBox control to true (word wrap on) or false (word wrap off).

In addition, we need to change the appearance of the menu item for the Word Wrap command to show a check mark when the Word Wrap is turned on (and no check mark when it is turned off).

Since the TextBox control's WordWrap property is a Boolean value (true or false), to "toggle" it (effectively turning word wrapping on and off) we negate its current value:

_textBox.WordWrap = !(_textBox.WordWrap);

For the menu item, we set the Checked property (also a Boolean value) to equal the value of the WordWrap property. This ensures that when word wrap is on (true), we have the menu item checked (true).

_miFormatWordWrap.Checked = _textBox.WordWrap;

Enabling and Disabling Menu Items
One of our goals with Netpad is to make the application intuitive. If the functionality provided by a menu item is not available, it should be disabled (greyed out) so the user cannot select it.

In Netpad, the Edit menu's Cut, Copy, and Delete commands should be available only when there is text selected in the text box. (Consider that these commands manipulate the selected text; if no text is selected, they do nothing. Good design dictates that they should be disabled in these situations.)

As well, the Edit menu's Select All command should be smart: if all the text is already selected, this option should be disabled. (You can't select all if all is already selected!)

To handle this, we will dynamically enable and disable each of these menu items when the user clicks on the Edit menu. The .NET Framework's MenuItem class has an event for this, called Popup. Whenever a user clicks on a menu item (such as our top-level Edit menu), before the menu is drawn on the screen, the Popup event occurs.

Our enabling and disabling logic will be written into a method which we'll name MenuEdit_Popup. There are three sections to this:

1.  If there's no text selected in our TextBox object, disable the Cut, Copy, and Delete menu items.

if ( _textBox.SelectionLength == 0 )
			_miEditCut.Enabled = false;
			_miEditCopy.Enabled = false;
			_miEditDelete.Enabled = false;

2.  If there is text selected in our TextBox object, enable the Cut, Copy, and Delete menu items.

else // !( _textBox.SelectionLength == 0 )
			_miEditCut.Enabled = true;
			_miEditCopy.Enabled = true;
			_miEditDelete.Enabled = true;

3.  Set the Select All menu item to be enabled if all text is not already selected. We check this by comparing the length of the selection (SelectionLength) to the length of the entire block of text (Text.Length).

_miEditSelectAll.Enabled = !( _textBox.SelectionLength == _textBox.Text.Length );

Putting It Together: Netpad, Phase 2
After compiling and running the complete source code for this article, you'll see that Netpad is much more usable. It now has clipboard support and some of the most useful functions in our model application, the Windows Notepad. Its menu items are responsive and intuitive.

However, there's still something missing that is very important: file operations. The next article in this series will outline the file opening and saving operations for Netpad.

More Stories By Brian DeMarzo

Brian DeMarzo has over 10 of years experience as a developer and systems engineer. He is an IT manager at a law firm in New York, a freelance consultant, the developer/designer of an online baseball game (www.csfbl.com), and developer and contributor to Marzie's Toolbox (www.marzie.com).

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.

IoT & Smart Cities Stories
Codete accelerates their clients growth through technological expertise and experience. Codite team works with organizations to meet the challenges that digitalization presents. Their clients include digital start-ups as well as established enterprises in the IT industry. To stay competitive in a highly innovative IT industry, strong R&D departments and bold spin-off initiatives is a must. Codete Data Science and Software Architects teams help corporate clients to stay up to date with the mod...
Tapping into blockchain revolution early enough translates into a substantial business competitiveness advantage. Codete comprehensively develops custom, blockchain-based business solutions, founded on the most advanced cryptographic innovations, and striking a balance point between complexity of the technologies used in quickly-changing stack building, business impact, and cost-effectiveness. Codete researches and provides business consultancy in the field of single most thrilling innovative te...
Darktrace is the world's leading AI company for cyber security. Created by mathematicians from the University of Cambridge, Darktrace's Enterprise Immune System is the first non-consumer application of machine learning to work at scale, across all network types, from physical, virtualized, and cloud, through to IoT and industrial control systems. Installed as a self-configuring cyber defense platform, Darktrace continuously learns what is ‘normal' for all devices and users, updating its understa...
At CloudEXPO Silicon Valley, June 24-26, 2019, Digital Transformation (DX) is a major focus with expanded DevOpsSUMMIT and FinTechEXPO programs within the DXWorldEXPO agenda. Successful transformation requires a laser focus on being data-driven and on using all the tools available that enable transformation if they plan to survive over the long term. A total of 88% of Fortune 500 companies from a generation ago are now out of business. Only 12% still survive. Similar percentages are found throug...
CloudEXPO has been the M&A capital for Cloud companies for more than a decade with memorable acquisition news stories which came out of CloudEXPO expo floor. DevOpsSUMMIT New York faculty member Greg Bledsoe shared his views on IBM's Red Hat acquisition live from NASDAQ floor. Acquisition news was announced during CloudEXPO New York which took place November 12-13, 2019 in New York City.
OpsRamp is an enterprise IT operation platform provided by US-based OpsRamp, Inc. It provides SaaS services through support for increasingly complex cloud and hybrid computing environments from system operation to service management. The OpsRamp platform is a SaaS-based, multi-tenant solution that enables enterprise IT organizations and cloud service providers like JBS the flexibility and control they need to manage and monitor today's hybrid, multi-cloud infrastructure, applications, and wor...
The Master of Science in Artificial Intelligence (MSAI) provides a comprehensive framework of theory and practice in the emerging field of AI. The program delivers the foundational knowledge needed to explore both key contextual areas and complex technical applications of AI systems. Curriculum incorporates elements of data science, robotics, and machine learning-enabling you to pursue a holistic and interdisciplinary course of study while preparing for a position in AI research, operations, ...
Atmosera delivers modern cloud services that maximize the advantages of cloud-based infrastructures. Offering private, hybrid, and public cloud solutions, Atmosera works closely with customers to engineer, deploy, and operate cloud architectures with advanced services that deliver strategic business outcomes. Atmosera's expertise simplifies the process of cloud transformation and our 20+ years of experience managing complex IT environments provides our customers with the confidence and trust tha...
With the introduction of IoT and Smart Living in every aspect of our lives, one question has become relevant: What are the security implications? To answer this, first we have to look and explore the security models of the technologies that IoT is founded upon. In his session at @ThingsExpo, Nevi Kaja, a Research Engineer at Ford Motor Company, discussed some of the security challenges of the IoT infrastructure and related how these aspects impact Smart Living. The material was delivered interac...
Intel is an American multinational corporation and technology company headquartered in Santa Clara, California, in the Silicon Valley. It is the world's second largest and second highest valued semiconductor chip maker based on revenue after being overtaken by Samsung, and is the inventor of the x86 series of microprocessors, the processors found in most personal computers (PCs). Intel supplies processors for computer system manufacturers such as Apple, Lenovo, HP, and Dell. Intel also manufactu...