
- •brief contents
- •about this book
- •The Windows Forms namespace
- •Part 1: Hello Windows Forms
- •Part 2: Basic Windows Forms
- •Part 3: Advanced Windows Forms
- •Who should read this book?
- •Conventions
- •Action
- •Result
- •Source code downloads
- •Author online
- •acknowledgments
- •about .NET
- •Casting the .NET
- •Windows Forms overview
- •about the cover illustration
- •Hello Windows Forms
- •1.1 Programming in C#
- •1.1.1 Namespaces and classes
- •1.1.2 Constructors and methods
- •1.1.3 C# types
- •1.1.4 The entry point
- •1.1.5 The Application class
- •1.1.6 Program execution
- •1.2 Adding controls
- •1.2.1 Shortcuts and fully qualified names
- •1.2.2 Fields and properties
- •1.2.3 The Controls property
- •1.3 Loading files
- •1.3.1 Events
- •1.3.2 The OpenFileDialog class
- •1.3.3 Bitmap images
- •1.4 Resizing forms
- •1.4.1 Desktop layout properties
- •1.4.2 The Anchor property
- •1.4.3 The Dock property
- •1.5 Recap
- •2.1 Programming with Visual Studio .NET
- •2.1.1 Creating a project
- •Action
- •Result
- •2.1.2 Executing a program
- •Action
- •Result
- •2.1.3 Viewing the source code
- •View the code generated by Visual Studio .NET
- •Action
- •Result
- •2.2 Adding controls
- •2.2.1 The AssemblyInfo file
- •Action
- •Results
- •2.2.2 Renaming a form
- •Action
- •Result
- •2.2.3 The Toolbox window
- •Action
- •Result
- •2.3 Loading files
- •2.3.1 Event handlers in Visual Studio .NET
- •Action
- •Result
- •2.3.2 Exception handling
- •Action
- •Result
- •Action
- •Results and Comments
- •2.4 Resizing forms
- •2.4.1 Assign the Anchor property
- •Action
- •Result
- •2.4.2 Assign the MinimumSize property
- •Action
- •Result
- •2.5 Recap
- •Basic Windows Forms
- •Menus
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •3.3 Click events
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •3.5 Context menus
- •Action
- •Result
- •Action
- •Result
- •3.6 Recap
- •Status bars
- •4.1 The Control class
- •4.2 The StatusBar class
- •Action
- •Result
- •Action
- •Result
- •4.3.1 Adding panels to a status bar
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •4.5 Recap
- •Reusable libraries
- •5.1 C# classes and interfaces
- •5.2 Class libraries
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •5.3 Interfaces revisited
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •5.4 Robustness issues
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Common file dialogs
- •Action
- •Results
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.3 Paint events
- •Action
- •Result
- •Action
- •Result
- •6.4 Context menus revisited
- •Action
- •Result
- •Action
- •Result
- •6.5 Files and paths
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.6 Save file dialogs
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.7 Open file dialogs
- •Action
- •Result
- •Action
- •Result
- •6.8 Recap
- •Drawing and scrolling
- •7.1 Form class hierarchy
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •7.4 Panels
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Dialog boxes
- •8.1 Message boxes
- •Action
- •Result
- •Action
- •Result
- •8.1.4 Creating A YesNoCancel dialog
- •Action
- •Result
- •Action
- •Result
- •8.2 The Form.Close method
- •8.2.1 The relationship between Close and Dispose
- •Action
- •Result
- •8.3 Modal dialog boxes
- •Action
- •Result
- •Action
- •Result
- •8.3.2 Preserving caption values
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Basic controls
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •9.1.2 Creating a derived form
- •Action
- •Result
- •9.2 Labels and text boxes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •9.3.6 Adding AlbumEditDlg to our main form
- •Action
- •Result
- •Action
- •Result
- •9.4 Recap
- •List controls
- •10.1 List boxes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.2 Multiselection list boxes
- •10.2.1 Enabling multiple selection
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.3 Combo boxes
- •Action
- •Result
- •Action
- •Result
- •10.4 Combo box edits
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.5 Owner-drawn lists
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •More controls
- •Action
- •Result
- •Action
- •Result
- •11.2 Tab pages
- •Action
- •Result
- •Action
- •Result
- •11.3.1 Dates and times
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •11.5 Recap
- •A .NET assortment
- •12.1 Keyboard events
- •Action
- •Result
- •Action
- •Result
- •12.2 Mouse events
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.3 Image buttons
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.4 Icons
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.5 Recap
- •Toolbars and tips
- •13.1 Toolbars
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •13.4.2 Creating tool tips
- •Action
- •Result
- •Action
- •Result
- •Advanced Windows Forms
- •List views
- •14.2 The ListView class
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •14.2.3 Populating a ListView
- •Action
- •Result
- •Action
- •14.3 ListView columns
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •14.6 Recap
- •Tree views
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.3 Dynamic tree nodes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.4 Node selection
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.5 Fun with tree views
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Multiple document interfaces
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.3 Merged menus
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.4 MDI children
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.5 MDI child window management
- •Action
- •Result
- •Action
- •Result
- •16.6 Recap
- •Data binding
- •17.1 Data grids
- •Action
- •Result
- •Action
- •Result
- •17.2 Data grid customization
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Odds and ends .NET
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •18.2 Timers
- •Action
- •Result
- •Action
- •Result
- •18.3 Drag and drop
- •Action
- •Result
- •Action
- •Result
- •18.4 ActiveX controls
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •18.5 Recap
- •C# primer
- •A.1 C# programs
- •A.1.1 Assemblies
- •A.1.2 Namespaces
- •A.2 Types
- •A.2.1 Classes
- •A.2.2 Structures
- •A.2.3 Interfaces
- •A.2.4 Enumerations
- •A.2.5 Delegates
- •A.3 Language elements
- •A.3.1 Built-in types
- •A.3.2 Operators
- •A.3.3 Keywords
- •A.4 Special features
- •A.4.1 Exceptions
- •A.4.2 Arrays
- •A.4.3 Main
- •A.4.4 Boxing
- •A.4.5 Documentation
- •.NET namespaces
- •B.1 System.Collections
- •B.2 System.ComponentModel
- •B.3 System.Data
- •B.4 System.Drawing
- •B.5 System.Globalization
- •B.6 System.IO
- •B.7 System.Net
- •B.8 System.Reflection
- •B.9 System.Resources
- •B.10 System.Security
- •B.11 System.Threading
- •B.12 System.Web
- •B.13 System.Windows.Forms
- •B.14 System.XML
- •Visual index
- •C.1 Objects
- •C.2 Marshal by reference objects
- •C.3 Components
- •C.4 Common dialogs
- •C.7 Event data
- •C.8 Enumerations
- •For more information
- •bibliography
- •Symbols
- •Index
1.2.3The Controls property
The final lines in the MyForm constructor add the button and picture box controls to the form using the Controls property. The Controls property returns an instance of the Control.ControlCollection class. The ControlCollection class is defined within the Form class, and defines an Add method that adds a control to a form. Note that the Controls property can be used to retrieve the controls on a form as well.
public MyForm()
{
. . .
// Add our new controls to the Form this.Controls.Add(btnLoad); this.Controls.Add(pboxPhoto);
}
When a control is added to a form, it is placed at the end of the z-order of the stack of controls on the form. The term z-order is used for both the set of forms in the application and the set of controls on a particular form, and indicates the order of windows stacked on the screen or controls stacked on a form, much like stacking dishes on a table.
The end of the z-order is bottom of the stack. You can think of this as the view a chandelier has of a table. If the tabletop is the form, and a cup and saucer are controls, in your code you would first add the cup control to the table, then add the saucer control so that it appears underneath the cup. This can be a bit unintuitive, so make sure you understand this point when programmatically adding controls to your forms.
The term z-order comes from the fact that the screen is two-dimensional, and is often treated as a two-axis coordinate system in the X and Y directions. The imaginary axis perpendicular to the screen is called the z-axis. This concept of z-order will be important later in the chapter when we have overlapping controls.
Now that our controls are placed on the form, we can use them to load and display an image.
1.3Loading files
The next change to our little program will permit the user to click the Load button and display a selected file in the picture box control. The result appears in figure 1.4, and looks very much like our previous screen, with the addition of the selected image.
18 |
CHAPTER 1 GETTING STARTED WITH WINDOWS FORMS |

Figure 1.4
The image loaded into the PictureBox control here is stretched to exactly fit the control’s display area.
Revise your program in accordance with listing 1.3. Once again the changes are shown in bold type, and the version number has been incremented, this time to 1.3.
Listing 1.3 The OpenFileDialog class is now used to load an image file
[assembly: System.Reflection.AssemblyVersion("1.3")]
namespace MyNamespace
{
using System;
using System.Drawing;
using System.Windows.Forms;
public class MyForm : System.Windows.Forms.Form
{
Button btnLoad;
PictureBox pboxPhoto;
public MyForm()
{
this.Text = "Hello Form 1.3";
// Create and configure the Button btnLoad = new Button(); btnLoad.Text = "&Load"; btnLoad.Left = 10;
btnLoad.Top = 10;
btnLoad.Click += new System.EventHandler(this.OnLoadClick);
// Create and configure the PictureBox pboxPhoto = new PictureBox();
pboxPhoto.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; pboxPhoto.Width = this.Width / 3;
pboxPhoto.Height = this.Height / 3;
pboxPhoto.Left = (this.Width - pboxPhoto.Width) / 2; pboxPhoto.Top = (this.Height - pboxPhoto.Height) / 2;
pboxPhoto.SizeMode = PictureBoxSizeMode.StretchImage;
LOADING FILES |
19 |

// Add our new controls to the Form
this.Controls.Add(btnLoad);
this.Controls.Add(pboxPhoto);
}
private void OnLoadClick(object sender, System.EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = "Open Photo";
dlg.Filter = "jpg files (*.jpg)|*.jpg|All files (*.*)|*.*" ;
if (dlg.ShowDialog() == DialogResult.OK)
{
pboxPhoto.Image = new Bitmap(dlg.OpenFile());
}
dlg.Dispose();
}
public static void Main()
{
Application.Run(new MyForm());
}
}
}
Note that there is a new namespace reference:
using System.Drawing;
This is required for the Bitmap class used to load the image file. As you’ll recall, the using keyword allows us to shorten to fully qualified name System.Drawing.Bitmap to the more manageable Bitmap. To include the definition of the Bitmap class, the System.Drawing.dll assembly is required when the program is compiled. The new compiler command for our program is below. Note that we use the short form /r of the /reference switch.
>csc MyForm.cs /r:System.dll /r:System.Windows.Forms.dll /r:System.Drawing.dll
Run the new program. Click the Load button and you will be prompted to locate a JPEG image file. If you do not have any such files, you can download some sample images from the book’s website at www.manning.com/eebrown. Select an image, and it will be loaded into the image window. Figure 1.4 shows a window with a selected image loaded. If you think this image looks a little distorted, you are correct. We’ll discuss this point in more detail later in the chapter.
As before, let’s take a look at our changes in some detail.
1.3.1Events
If you think about it, Windows applications spend a large amount of time doing nothing. In our example, once the window is initialized and controls drawn, the
20 |
CHAPTER 1 GETTING STARTED WITH WINDOWS FORMS |
application waits for the user to click the Load button. This could happen immediately or hours later. How an application waits for such user interactions to occur is an important aspect of the environment in which it runs. There are really only two possible solutions: either the application has to check for such actions at regular intervals, or the application does nothing and the operating system kicks the program awake whenever such an action occurs.
Waiting for a user action can be compared to answering the phone. Imagine if there were no ringer and you had to pick up your phone and listen for a caller every couple of minutes to see if someone was calling. Even ignoring the extra time a caller might have to wait before you happened to pick up the receiver, it would be difficult to perform any other activities because you would constantly have to interrupt your work to check the phone. The ringer allows you to ignore the phone until it rings. You can fall asleep on the couch while reading this book (not that you would, of course) and rely on the phone to wake you up when someone calls (unless you turn off the ringer, but that is a separate discussion).
Similarly, Windows would grind to a halt if applications were actively looking for user actions all the time. Instead, applications wait quietly on the screen, and rely on the operating system to notify them when an action requires a response. This permits other applications to perform tasks such as checking for new email and playing your music CD between the time you run a program and actually do something with it. The interval between running the program and using it may only be seconds, but to a computer every fraction of a second counts.
Internally, the Windows operating system passes messages around for this purpose. When the user clicks the Load button, a message occurs that indicates a button has been pressed. The Application.Run method arranges for the application to wait for such messages in an efficient manner.
The .NET Framework defines such actions as events. Events are pre-defined situations that may occur. Examples include the user clicking the mouse or typing on the keyboard, or an alarm going off for an internal timer. Events can also be triggered by external programs, such as a web server receiving a message, or the creation of a new file on disk. In C#, the concept of an event is built in, and classes can define events that may occur on instances of that class, and enable such instances to specify functions that receive and process these events.
While this may seem complicated, the result is simply this: when the user clicks the mouse or types on the keyboard, your program can wake up and do something. In our program, we want to do something when the user clicks the Load button. The Button class defines an event called Click. Our program defines a method called OnLoadClick to handle this event. We link these two together by registering our method as an event handler for the Click event.
btnLoad.Click += new System.EventHandler(this.OnLoadClick);
LOADING FILES |
21 |