BUY THIS BOOK
Add to Cart

Print Book $44.95


Safari Books Online

What is this?

Add to UK Cart

Print Book £31.95

What is this?

Looking to Reprint this content?


.NET Windows Forms in a Nutshell
.NET Windows Forms in a Nutshell

By Ian Griffiths, Matthew Adams
Price: $44.95 USD
£31.95 GBP

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: .NET and Windows Forms Overview
In early 2002, Microsoft shipped .NET, a suite of new technologies for Windows first announced in the summer of 2000. The attendant media frenzy concentrated on its support for web services, but .NET has far greater scope than that—it could change the way all Windows programs are written. .NET offers greatly improved productivity to developers by replacing swathes of the Win32 API with new, much higher level object-oriented APIs, allowing you to focus on the task at hand without being distracted by myriad petty details.
This book is about the technology behind Windows applications that run on this new .NET platform. In particular, it focuses on rich client applications—i.e., traditional interactive programs with a graphical user interface (GUI) that run locally on your computer. Although web applications have become very popular in recent years, experience with these thin clients has taught us that there is still very much a place for the more traditional style of Windows application. If you've ever had to switch from Outlook to a web mail service when working away from the office, you know just how much web applications leave to be desired.
The new programming interface for writing Windows applications with GUIs is called Windows Forms. This replaces all the old programming models, and not just the C++ favorites, such as MFC or raw Win32, but also the Forms package used in Visual Basic 6.0 and earlier. Windows Forms combines the best features from all these models, and it is the long term future of Windows development.
It is important to understand why Microsoft decided to make such sweeping changes to Windows software development. Deprecating all the APIs used by the vast majority of programs seems like a wildly irresponsible move calculated to alienate anyone who ever wrote a Windows application. And yet, the majority of developers who look at .NET in any detail soon become big fans, especially those from a C++ background.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Windows Development and .NET
It is important to understand why Microsoft decided to make such sweeping changes to Windows software development. Deprecating all the APIs used by the vast majority of programs seems like a wildly irresponsible move calculated to alienate anyone who ever wrote a Windows application. And yet, the majority of developers who look at .NET in any detail soon become big fans, especially those from a C++ background.
.NET raises the level of abstraction that developers work with—almost every service provided by the platform is now exposed through a higher-level programming interface than before. In Win32, the API was procedural in that all services were accessed through C function calls, using opaque handles to represent entities that outlived single function calls (e.g., windows or files). Developers had to expend a lot of effort dealing with low-level details such as memory management, which as the lucrative market in memory leak detection tools illustrates, was a source of much grief. By contrast, .NET provides all its services through a class library, and many low-level programming details are now dealt with by the platform (for example, the .NET runtime manages memory with a garbage collection scheme).
Veteran MFC or WTL developers might well point out that they have always used object-oriented abstractions for constructs such as windows and files. And Visual Basic developers can equally remind us that they have never had to deal with low-level minutiae. However, all these programming systems suffer from being wrappers on top of the "real" API, Win32. This is problematic because none of them provides a watertight abstraction—the underlying API is forever making its presence felt. This is particularly intrusive with the C++ class libraries: it's just not possible to write a nontrivial C++ Windows application without having to deal with some Win32 construct sooner or later.
Visual Basic does slightly better—it has enabled many people to become productive developers without ever understanding how Windows really works at the lowest levels. But Visual Basic runs into trouble as soon as you need to do something that it wasn't designed to support. It relies on ActiveX controls or COM components to exploit certain platform services, which is fine when such a component exists, but it means that support for the latest features of the OS can be somewhat late in arriving. While C++ developers can use new features as soon as they appear, Visual Basic developers must wait for a C++ developer to write them an ActiveX control. Visual Basic also suffers from a slightly more insidious problem. The high-level model it presents is a simplification of the Win32 model, and as such it differs in certain respects. If you write nothing but data entry forms this will almost certainly never cause you any problems, but if you need to exercise fine control over an application's behavior, Visual Basic's supposedly helpful model can sometimes be extremely frustrating.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Common Language Runtime
The Common Language Runtime (CLR) is the environment in which all programs run in .NET, so it affects everything we do as developers. It is therefore important to understand what it does and what that means to our programs, so we will now look at the most important features of the CLR.
All high-level programming languages have a runtime. This is because an OS process provides a fairly low-level set of features, typically just memory, pointers, threads, machine code, and system calls. The job of any language's runtime is to bridge the gap between these OS facilities and the constructs defined by the programming language. In C++, the runtime provides such features as exception handling, runtime type information, and the standard C++ library. The Visual Basic runtime includes intrinsic handling for COM and automatic memory management. Traditionally, each language has provided its own runtime, such as MSVCRT.DLL for C++, MSVBVM60.DLL for Visual Basic, and the Java Virtual Machine (MSJAVA.DLL, if you're using Microsoft's VM) for Java.
In .NET, there is just one runtime, which is used by all languages, the CLR. The fact that all languages use this one runtime is important for a number of reasons. It means components can easily be written in and used from any language because all languages represent types and objects in the same way. (Anyone familiar with COM in C++ will be amazed at how simple it is to write and use .NET components.) Moreover, it means that all languages can use the same API to access the platform's services.
C++ developers are used to writing low-level code. All the abstractions with which Win32 assembly language developers work (virtual memory, threads of execution, numbers, and pointers) are also exposed directly in C++. (Yes, there are still a few diehards who insist on writing Win32 applications in assembly language.) The C++ compiler supplies a useful veneer on top of these, providing facilities such as object-oriented programming and optional type safety, but the fact remains that all the platform's lowest level details are visible. For many developers, this is the appeal of C++—it hides nothing, imbuing the developer with a feeling of ultimate power.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
.NET Programming Languages
.NET has been designed to support multiple languages. Microsoft anticipates that most Visual Basic developers will want to carry on using the syntax they are familiar with, and will therefore stick with Visual Basic .NET. But developers with a C++ background are encouraged to change to a new language called C#. The problem with C++ is it is designed to support a very low-level style of programming—it fully supports all the classic C idioms, and C has often been described as a machine-independent assembly language. The low-level nature of C++ does not sit well with the new high-level nature of the CLR and the class libraries. (Visual Basic does not have this problem because it has always been a relatively high-level language.)
Although C++ is supported in .NET, it is not being pushed as the language of choice for erstwhile C++ developers. Instead, Microsoft has created a new language called C#. Designed by Anders Hejlsberg (creator of Delphi), C# is a language with syntax based on C++, but that works natively with exactly the same set of abstractions as the CLR provides. Just as C++ was the natural choice for developers who wanted to write code that was at home in the Win32 world, C# is a great choice for .NET programming, because it was designed to be a perfect match for the CLR. Its syntactic origins mean that anyone familiar with C or C++ (or Java) can learn C# very quickly.
For the most part, C# is like C++ without the low-level grunge. In fact, it is possible to use C-style features like pointers even in C#, although you need to turn off the relevant safety catches on the compiler before it will let you do this. However, this is mostly to make sure that C++ developers don't feel emasculated by moving to C#. While it is comforting for C++ veterans to know that pointers are still there if required, in practice, it is extremely rare to need to use these features in C#.
All example code in this book is presented in both C# and Visual Basic .NET, because the majority of Windows applications will be written in one or the other of these languages in the future.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Components
Whatever language we build our software in, we end up creating executable files that are loaded and run by the operating system. In days gone by, software was monolithic in nature—all the code and data required for an application was compiled and linked into a single executable lump of code. While there may be a certain elegant simplicity to this approach, it did little to encourage code reuse. It also tended to encourage a programming style sometimes referred to as the "big ball of mud," where any individual part of the code is messily intermingled with lots of other parts, and there is no overall structure to the code. This was not especially conducive to code quality or developer productivity, and in extreme cases, a software project could become so entangled and intractable that fixing one bug could easily introduce several more bugs due to the unforeseen side effects of the change. The object-oriented (OO) features of C++ were not a sure-fire solution to this problem, because unless developers were scrupulous about encapsulating their code and keeping classes independent of each other, all the same problems could emerge in an OO program.
Component-based software development was one of the most significant advances in software engineering to be adopted over the last decade. Componentized applications are not monolithic—they are broken down into discrete chunks (or components) with clear roles and well-defined boundaries. A key feature is that software components are binaries (i.e., compiled executables rather than collections of source code). This has the effect of preventing unrelated parts of the system from gradually merging just because of expediency—it means there are always clear divisions between parts of the system. This is particularly true if the individual components are developed by different groups: if there are any structural problems with the code, these must be dealt with by fixing the problems rather than resorting to hacks to work around them.
Of course, it is possible to write bad code in any programming system, and .NET doesn't change that. As always, there is no silver bullet. But with component-based systems like .NET, developers have to go out of their way to make one component depend on internal features of another component, so at least it encourages better practice, even if it can't enforce it.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The .NET Type System
So what does a type look like in .NET? In many respects, types are very similar to C++ classes: just like a C++ class, a .NET type is a collection of members, which may be fields (i.e., they hold data of some type), methods (i.e., they contain code), or nested type definitions, and all members have some level of protection (e.g., public, private, protected). However there are a number of differences between the C++ and the .NET type systems. The following sections describe the main features of types in .NET.
Any type will need to define some members to be of any use. Members are either associated with data or behavior. In C++ this means fields and methods, respectively. In addition to these, which the CLR supports, the CLR adds some new member types. All these member types are described here.

Section 1.5.1.1: Methods

Methods are where we define code. In most .NET languages, all code must be defined in a method of some type. (Because properties also can contain code, they would appear to be an exception, but they are actually implemented by .NET language compilers as method calls.) As with C++, the method must have a signature (consisting of its name and the types of parameters it takes), and that signature must be different from any other methods defined in the same class. Overloading is allowed, i.e., the names of two methods can be the same if their signatures are different. Methods must also have a return type (even if the method returns void or Nothing); overloading based on return type alone is not allowed. (C++ doesn't allow this either.) Note that methods that return void or Nothing in VB are declared using the Sub statement rather than the Function statement.
Methods can either be instance methods or static methods. (Instance methods are the default, but you can use the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The .NET Framework Class Library
All platform services are exposed through the .NET Framework Class Library. So whether you want to make a window appear, read a file, open a network connection, parse an XML document, or use any of the other myriad features of the platform, you will do so by using one or more classes in the class library.
The class library is divided up into namespaces . For each area of the API, there is an appropriate namespace, e.g., XML services are provided by the System.Xml namespace, GUI services are provided by the System.Windows.Forms namespace, and graphical services are provided by the System.Drawing namespace. Namespaces are hierarchical, and large namespaces are frequently subdivided into several smaller namespaces, e.g., the design-time parts of the Windows Forms API appear in the System.Windows.Forms.Design namespace.
Because the Class Library replaces large amounts of the Win32 API, and also adds new functionality not previously available, it is large and contains many namespaces. This book concentrates on the Windows Forms namespace, and the related System.Drawing namespace, although we will discuss other relevant classes as necessary.
Windows Forms is the name given to the parts of the .NET Framework Class Libraries used for building rich client applications, i.e., traditional GUI applications such as those built using the MFC before .NET. Central to Windows Forms is the Control class, the foundation of all UI applications and the subject of the next chapter. In fact, almost everything that happens in a .NET UI application revolves around controls, so most of the rest of the book is about controls.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Controls
The System.Windows.Forms namespace defines a class called Control. This class is at the heart of all Windows Forms applications. Any visual element of an application—whether it is a window, a button, a toolbar, or a custom user-defined control—is represented by an object of some class deriving from Control.
This chapter describes the role played by the Control class within the Windows Forms framework, and examines the basic behavior that all controls inherit from Control. It also introduces the classes that represent the traditional Windows controls.
Each different type of user interface element is represented by a specialized class deriving from Control. For example, top-level windows are represented by the Form class; each of the standard Windows control types has a corresponding class (such as Button and TreeView); you can also define custom controls by creating your own classes. All these inherit (either directly or indirectly) from the Control class.
Because all visual elements derive from Control, they share a single implementation of the features common to all controls. This ensures a certain minimum level of functionality and guarantees consistent behavior across all control types. The Control class defines standard properties, events, and methods for all the common features of user interface components. These include size and position, input handling, and appearance.
The Control class also defines the nature of the relationships controls on a form have with one another. As with classic Windows programming, a parent-child relationship is supported—a control may contain several child controls, and most controls (except top-level windows) have a parent control. The containment relationship is detailed in the next chapter, but it affects all controls for certain operations, such as moving and resizing windows. It also has some slightly more subtle implications for features such as focus management and control validation.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Windows Forms and the Control Class
Each different type of user interface element is represented by a specialized class deriving from Control. For example, top-level windows are represented by the Form class; each of the standard Windows control types has a corresponding class (such as Button and TreeView); you can also define custom controls by creating your own classes. All these inherit (either directly or indirectly) from the Control class.
Because all visual elements derive from Control, they share a single implementation of the features common to all controls. This ensures a certain minimum level of functionality and guarantees consistent behavior across all control types. The Control class defines standard properties, events, and methods for all the common features of user interface components. These include size and position, input handling, and appearance.
The Control class also defines the nature of the relationships controls on a form have with one another. As with classic Windows programming, a parent-child relationship is supported—a control may contain several child controls, and most controls (except top-level windows) have a parent control. The containment relationship is detailed in the next chapter, but it affects all controls for certain operations, such as moving and resizing windows. It also has some slightly more subtle implications for features such as focus management and control validation.
The Windows Forms framework defines a class hierarchy for the various kinds of controls. The Control class sits at the root of this hierarchy, but there are specializations for various types of controls, as Figure 2-1 shows. All the built-in controls (buttons, labels, tree views, etc.) inherit directly from the Control class. As you will see in Chapter 5, you can write your own controls that do the same.
Figure 2-1: The Control class hierarchy
In practice, most user-defined controls only inherit indirectly from the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using Standard Control Features
The Control class provides uniform management of all the standard facets of a control, including visual features such as color, caption, and typeface, dynamic features such as event handling and accessibility, and other standard behaviors such as layout management. There are two ways of using most of these features: at design time in the Windows Forms designer and at runtime from code.
The Windows Forms designer allows most of the features of a control to be configured visually at design time using the Properties tab. (Also, certain common operations can be performed directly with the mouse; for example, the position of a control can be adjusted by dragging it.) However, this visual editing simply causes the designer to generate code. It just writes a class that creates control objects and manipulates their properties. Unlike earlier Windows development environments, .NET doesn't have dialog template resources—everything is done in code. (The strings used in a form can be stored as resources, though, to support localization.) For example, dropping a button onto a form in the designer causes the following code to be added to the form's class definition for projects written in C#:
private System.Windows.Forms.Button button1;
...
private void InitializeComponent()
{
    ...
    this.button1 = new System.Windows.Forms.Button();
    ...
    this.button1.Location = new System.Drawing.Point(8, 8);
    this.button1.Name = "button1";
    this.button1.TabIndex = 0;
    this.button1.Text = "button1";
    ...
}
The corresponding code for projects written in VB is:
Private WithEvents Button1 As System.Windows.Forms.Button

Private Sub InitializeComponent()

   Me.Button1 = New System.Windows.Forms.Button()
   Me.SuspendLayout()
   '
   'Button1
   '
   Me.Button1.Location = New System.Drawing.Point(8, 8)
   Me.Button1.Name = "Button1"
   Me.Button1.TabIndex = 0
   Me.Button1.Text = "Button1"
   ...
End Sub
So using the designer is functionally equivalent to writing the code by hand, although it is rather more convenient. The mechanisms through which we use controls are the methods, properties, and events that they expose (just as with any other component in .NET). The Windows Forms designer is effectively just a code generation mechanism. Because the programming model provided by the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Built-in Controls
Windows provides several kinds of widely used controls, such as buttons and text boxes, which act as the fundamental building blocks in most user interfaces. All these standard control types have .NET equivalents. This section shows which controls are available and what their Win32 equivalents are. It also describes some of the issues common to all the standard controls. More detailed technical descriptions of each control can be found in the reference section.
Table 2-1 shows the list of available controls and the nearest equivalent window class in Win32. (Some Win32 classes, such as Button, have several different modes, each of which is represented by a different class in Windows Forms. In this case, a Win32 window style is also specified to indicate which particular flavor of this class the relevant .NET type represents.)
Table 2-1: .NET controls and their equivalent Win32 control classes
Control class
Equivalent Win32 window class (and style)
Purpose
Buttons
Button
Button 
(BS_PUSHBUTTON)
Normal button for actions (e.g., OK or Cancel)
CheckBox
Button (BS_CHECKBOX)
Yes/no selection button
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
The Control class is central to any Windows Forms application. Every visible element of the user interface is a control of some kind. This means there is a rich standard set of features that all controls support. All the standard Windows controls have counterparts in Windows Forms.
In the next chapter we will look in more detail at how controls work together on a form to provide a cohesive user interface.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Forms, Containers, and Applications
Any interactive application must have at least one window through which to present its user interface. In the Windows Forms framework, all such top-level application windows are represented by objects whose types derive from the Form class. As with any user interface element, the Form class inherits from the Control class, but it adds windowing features, such as management of the window border and interaction with the Windows taskbar. All Windows Forms applications have at least one class derived from Form.
In this chapter we will examine the structure of a typical Windows Forms application and the way its constituent forms are created. We will look at the programming model for forms, and the way that the Visual Studio .NET Forms Designer uses this model. We will look in detail at the relationship between a form and the controls it contains, and also at the relationships that can exist between forms. The mechanisms underpinning the automatic layout features described in the previous chapter will be examined, and we will see how to use these to add our own custom layout facilities.
All Windows Forms applications have something in common, regardless of whether they are created with Visual Studio .NET or written from scratch:
  • They all have at least one form, the main application window.
  • They all need to display that form at start up.
  • They must shut down correctly at the appropriate time.
This section describes the basic structure that all applications have and the way that their lifetime is managed by the .NET Framework.
All programs have to start executing somewhere, and .NET applications have a special method that is called when the application is run. This method is responsible for creating whatever windows the application requires and performing any other necessary initialization.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Application Structure
All Windows Forms applications have something in common, regardless of whether they are created with Visual Studio .NET or written from scratch:
  • They all have at least one form, the main application window.
  • They all need to display that form at start up.
  • They must shut down correctly at the appropriate time.
This section describes the basic structure that all applications have and the way that their lifetime is managed by the .NET Framework.
All programs have to start executing somewhere, and .NET applications have a special method that is called when the application is run. This method is responsible for creating whatever windows the application requires and performing any other necessary initialization.
In C# and Visual Basic, this entry point is always a static method called Main . It doesn't matter which class this is defined in, although Visual Studio always makes it a member of the main form that it puts in any new project. It generates code like the C# code shown in Example 3-1.
Example 3-1. A typical application entry point
[STAThread]
static void Main() 
{
    Application.Run(new Form1());
}
Although Visual Studio makes Main visible if you're developing with C#, it hides it if you're developing with Visual Basic. In Visual Basic projects, the code for Main is not displayed in the form's code window, nor is it listed in Class View or in the Object Browser. However, examining a compiled Windows Forms application using ILDASM, the .NET disassembler, indicates that a hidden public method named Main is present in the application's main form, as Figure 3-1 shows. Its source code corresponds to that shown in Example 3-2.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Form Class
All windows in a Windows Forms application are represented by objects of some type deriving from the Form class. Of course, Form derives from Control, as do all classes that represent visual elements, so we have already seen much of what it can do in the previous chapter. But we will now look at the features that the Form class adds.
You will rarely use the Form class directly—any forms you define in your application will be represented by a class that inherits from Form. Adding a new form in Visual Studio .NET simply adds an appropriate class definition to your project. We will examine how it structures these classes when generating new forms, and we will look at how it cleans up any resource used by the form when it is destroyed. Then, we will consider the different types of forms. Finally, we will look at extender properties. These provide a powerful way of extending the behavior of all controls on a form to augment the basic Control functionality.
Most forms are designed using the Forms Designer in Visual Studio .NET. This is not an essential requirement—the designer just generates code that you could write manually instead. It is simply much easier to arrange the contents of a form visually than it is to write code to do this.
When you add a new form to a project, a new class definition is created. The Designer always uses the same structure for the source code of these classes. They begin with private fields in C# and Friend fields in VB to hold the contents of the form. (The Designer inserts new fields here as you add controls to the form.) Next is the constructor, followed by the Dispose and InitializeComponent methods; these are all described below. If this is the main form in your application, the program's entry point (the Main method described above) will follow in C# programs; in VB programs, it will be added by the compiler at compile time, but will not be displayed with the form's source code. Finally, any event handlers for controls on your form will be added at the end of the class.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Containment
All useful forms contain some controls. There is more to this containment relationship than meets the eye, and if you are familiar with the old Win32 parent/child relationship, you will find that things do not work in quite the same way. We will look at the control nesting facilities supplied by both the Control class and the ContainerControl class, paying particular attention to the implications of containment for focus and validation events.
Controls rarely exist in complete isolation—top-level windows usually contain some controls, and all non-top-level controls are associated with a window. In fact, Windows Forms defines two kinds of relationships between controls. There is the parent/child relationship, which manages containment of controls within a single window. There is also a looser association that can exist between top-level windows, which is represented by the owner/owned relationship.

Section 3.3.1.1: Parent and child

A child window is one that is completely contained by its parent. For example, any controls that you place on a form are children of that form. A child's position is specified relative to its parent, and the child is clipped to the parent's bounds—i.e., only those parts of the child completely inside the parent are visible. Forms can be children too: document windows in an MDI application are children of the main MDI frame.
A control's parent is accessible through its Parent property (of type Control). If you examine this property on a control on a form, you will typically find that it refers to that form. However, many controls can behave as both a parent and a child—if you place a button inside a group box on a form, the button's parent will be the group box, and the group box's parent will be the form.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Layout
As we saw in the previous chapter, the framework can modify a control's position and size automatically. We looked at the docking and anchoring facilities, but Windows Forms provides support for other styles of layout. The simplest of these is a fixed layout in a scrollable window. Splitter support is also built in. In this section, we will look at all these styles of layout, and then examine the mechanism in the framework that underpins them all. It is possible to extend the layout facilities to provide your own automatic layout strategies. We will look at the standard events that support this, and then see a simple example custom layout engine.
Windows Forms provides a facility for enabling the contents of a control to exceed the control's size on screen, and for scrollbars to be added automatically to enable the user to access all of it. This functionality is provided by the ScrollableControl class. This is the base class of ContainerControl and of Panel, which means that this behavior is available to all forms, panels, and user controls.
To enable automatic scrolling management, simply set the AutoScroll property to true. If the window is smaller than its contents, scrollbars will be added automatically. Of course, the class will need some way of knowing how large the window's contents are. By default, it will deduce this from its child controls—it will assume that the window's size should be exactly large enough to hold all the controls.
Because automatic scrolling will make the scrollable area exactly large enough to hold the controls and no larger, the controls will be right up against the edge of the window when it is scrolled as far down or across as it can go. However, you can add some padding by setting the AutoScrollMargin property. This property's type is Size, which enables you to specify the vertical padding and the horizontal padding separately. So specifying a margin of
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Localization
The software market is a global one, and many programs will ship in regions where the users' first language will be different from the application developers' native tongue. While many software products get away with making the highly parochial assumption that everybody speaks English, .NET lets us do better than that. It provides support for building applications that support multiple languages.
The .NET Framework supplies facilities for localization of resources such as strings and bitmaps, and the Forms Designer can create forms that make use of this. To understand how to create localizable user interfaces, it is first necessary to understand the underlying localization mechanism that it is based on, so we will first look at global resource management, and then we will see how it is applied in a Windows Forms application.
The programming model for localizable applications is based on a simple premise: whenever you require information that might be affected by the current language, you must not hardcode this information into your application. All such information should be retrieved through a culture-sensitive mechanism. (In .NET, the word culture is used to describe a locality; it implies all the relevant information, such as location, language, date formats, sorting conventions, etc.) The mechanism we use for this is the ResourceManager class, which is defined in the System.Resources namespace.
The ResourceManager class allows named pieces of data to be retrieved. (We'll see where this data is stored in just a moment.) For example, rather than hardcoding an error message directly into the source, we can do the following in C#:
ResourceManager resources = new ResourceManager(typeof(MyForm));
string errorWindowTitle = resources.GetString("errorTitle");
string errorText = resources.GetString("errorFileNotFound");
MessageBox.Show(errorText, errorWindowTitle);
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Extender Providers
Although the Control class provides a very rich set of features, inevitably it cannot be all things to all people. UI innovations continue to emerge, so even if the Control class were to represent the state of the art today, in time, it would inevitably end up looking short on features.
However, Windows Forms provides a very useful way of extending the abilities of the basic Control class. It is possible to place a component on a form that adds a feature to every single control on that form. Such a component is referred to as an extender provider. We will see how to write extender providers in Chapter 9, but no discussion of forms would be complete without looking at how to use them.
The Forms Designer supports extender providers. An extender provider can add new properties to all controls on a form. An example of this in the Windows Forms framework is the ToolTip class. As mentioned in Chapter 2, the Control class does not provide ToolTip support. But this doesn't matter—the framework has a ToolTip class that is able to augment any control with ToolTip support. If you drop the ToolTip component onto a form, it will appear in the component tray at the bottom of the designer. (All non-UI components appear here; the only kind of component that has any business appearing on the form at design time is a control, so everything else appears in the component tray. And the ToolTip isn't strictly a UI component; it is a component that modifies the behavior of other controls.) Once you have done this, if you look at the Properties tab for any of the controls on your form, you will see that each has acquired a ToolTip property in the Misc category. If you set some text for this property for a particular control, that text will appear as a ToolTip whenever the mouse hovers over that control at runtime.
Of course, the classes representing each control haven't really grown a new property—.NET doesn't allow class definitions to change at runtime. The extra property is an illusion presented by the Designer. If you set the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
All Windows Forms applications have at least one window in them, and each window is represented by an object whose class derives from the Form class. These classes are typically generated by the Visual Studio .NET forms designer, which uses a standard structure for handling initialization and shutdown. An application could have just one form or it might have several, but in any case, its lifetime is managed by the Application class. The controls in a form can have their layout managed automatically, and while there are several built-in styles of automatic layout, the underlying mechanisms are also exposed, allowing custom automatic layout systems to be written. Another useful feature of forms is the ability to use an extender provider—these are components which add pseudo properties (so-called extender properties) to some or all the controls on a form, allowing the basic functionality of the Control class to be augmented.
Of course, a great many Windows applications adorn their forms with menus, so in the next chapter we'll look at how to add menus to your applications.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Menus and Toolbars
Menus are often the only practical way to present a rich array of functionality without cluttering up the user interface. Whether appearing at the top of the window, or as a context menu accessed through the righthand mouse button, menus allow an application to show concisely which operations are available. An application's usability can be further enhanced by making the most important operations available through toolbar buttons as well as menus.
The Windows Forms framework provides support for both menus and toolbars. Despite the fact that these two technologies serve similar roles—toolbar buttons often correspond directly to menu items—they are presented through two largely unrelated parts of the class library. However, as we will see later, it is possible to unify the way you handle events from them in your application.
In this chapter, we will first examine the support for menus. Then we will see how to create toolbars. Finally, we will see how events from both can be dealt with by a single set of event handlers.
The Windows Forms framework provides support for adding menus to your applications. It uses a single programming model both for normal window menus and for context menus. The model allows menus to be modified dynamically, or even combined, providing flexibility at runtime, and supports the ability to reuse and extend menu definitions.
We will start by examining the object model used for constructing menus. Then we will see how to attach them to a form. Next, we will look at how to add context menus. Finally, we will see how to reuse and extend your menu definitions by merging items from one menu into another, both in the context of MDI applications, and also when reusing forms through inheritance.
For your application to use menus, you must provide Windows Forms with a description of their structure and contents. You do this by building hierarchies of objects that represent menus and the items they contain. Although you will typically get Visual Studio .NET to do this for you, a sound understanding of the object model it uses is important to use menus effectively in your applications.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Menus
The Windows Forms framework provides support for adding menus to your applications. It uses a single programming model both for normal window menus and for context menus. The model allows menus to be modified dynamically, or even combined, providing flexibility at runtime, and supports the ability to reuse and extend menu definitions.
We will start by examining the object model used for constructing menus. Then we will see how to attach them to a form. Next, we will look at how to add context menus. Finally, we will see how to reuse and extend your menu definitions by merging items from one menu into another, both in the context of MDI applications, and also when reusing forms through inheritance.
For your application to use menus, you must provide Windows Forms with a description of their structure and contents. You do this by building hierarchies of objects that represent menus and the items they contain. Although you will typically get Visual Studio .NET to do this for you, a sound understanding of the object model it uses is important to use menus effectively in your applications.
This object model revolves around the Menu class, which is arguably misnamed, because it represents a more abstract concept than its title suggests. It can correspond to any element of a menu structure, and it is the base class of all the other types in the menu object model. So while a Menu object might represent a menu, it could just represent a single item of a menu. (Perhaps MenuElement would have been a more descriptive name.) Representing menus and menu items with the same base type seems a little strange at first, but it makes sense when you consider that menus can be hierarchical. A menu item might well be a nested menu, in which case, it makes sense for that menu item to be represented by an object whose class derives from Menu.
The main job of the Menu class is to represent the structure of a menu. You can find out whether a particular
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Toolbars
Toolbars usually provide access to features that are also accessible through menus, but there's a tradeoff. Because a toolbar is always visible, it can be clicked without having to navigate through a menu structure, but toolbars have a slightly higher learning curve, because items are normally represented by buttons with a small bitmap; it is much harder to represent an operation unambiguously with a tiny picture than it is to describe it with some text in a menu.
In Windows Forms, toolbars are represented by the ToolBar class, and individual buttons on it are represented by the ToolBarButton class. Note that these classes provide a fairly basic style of toolbar—Windows Forms provides no support for undocking toolbars or even rearranging them.
ToolBar is a fairly simple class. It inherits from Control and must be docked; most applications dock the toolbar to the top of the window. ToolBar is a simple class to use—it adds only a few properties to its base class.
The class provides an Appearance property, which must be one of the members of the ToolBarAppearance enumeration: either Normal (the default) or Flat. When set to Normal, each toolbar button has a button-like raised edge. However, most applications favor the Flat style these days, where the toolbar appears completely flat, and the buttons have no outline except when the mouse is over them.
The ToolBar also controls where any text associated with a button appears through its TextAlign property. (A toolbar button may optionally have a text label, like the Back button on Internet Explorer.) This property's type is the ToolBarTextAlign enumeration, and it can be either Right or Underneath. The default is Underneath.
The most important property of a toolbar is Buttons , whose type is ToolBarButtonCollection. This contains all the ToolBarButton objects on the toolbar. This is used in a similar way to the other collections we have seen, such as the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Unified Event Handling
The majority of toolbar buttons act as shortcuts to menu items, so it makes sense to handle equivalent clicks with a single event handler. Unfortunately, Windows Forms does not provide a direct way of doing this. However, it is fairly easy to arrange such a scheme. We can write an event handler for the toolbar that locates the appropriate menu item and then calls its event handler.
All we need is some way of associating toolbar buttons with menu items. For this, we can use a class provided by the .NET Framework class libraries called System.Collections.Hashtable—it is designed to store associations between objects. We can use this to remember which toolbar buttons are equivalent to which menu items. Although the Designer cannot store these associations in a hash table for you automatically, it only requires a small amount of code in your form's constructor. The following is the necessary C# code:
// Hashtable to associate buttons with menu items
private Hashtable toolbarButtonToMenu;
public MyForm()
{
    InitializeComponent();

    // Create hash table
    toolbarButtonToMenu = new Hashtable();

    // Associate ToolBarButtons with MenuItems
    toolbarButtonToMenu(toolBarFileNew)    = menuFileNew;
    toolbarButtonToMenu(toolBarFileOpen)   = menuFileOpen;
    toolbarButtonToMenu(toolBarEditCopy)   = menuEditCopy;
    toolbarButtonToMenu(toolBarEditCut)    = menuEditCut;
    toolbarButtonToMenu(toolBarEditPaste)  = menuEditPaste;
    toolbarButtonToMenu(toolBarEditDelete) = menuEditDelete;
}
The following is its VB equivalent:
' Hashtable to associate buttons with menu items
Private toolbarButtonToMenu As HashTable

Public Sub New()

    InitializeComponent()

    ' Create hash table
    toolbarButtonToMenu = New Hashtable()

    ' Associate ToolBarButtons with MenuItems
    toolbarButtonToMenu(toolBarFileNew)    = menuFileNew
    toolbarButtonToMenu(toolBarFileOpen)   = menuFileOpen
    toolbarButtonToMenu(toolBarEditCopy)   = menuEditCopy
    toolbarButtonToMenu(toolBarEditCut)    = menuEditCut
    toolbarButtonToMenu(toolBarEditPaste)  = menuEditPaste
    toolbarButtonToMenu(toolBarEditDelete) = menuEditDelete
End Sub
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Office-Style Menus and Toolbars
The Microsoft Office suite provides menus and toolbars that are a little different from the standard ones. Menu items have icons next to them, usually matching the icons used in the toolbar. The latest versions have the new "flat" look. (Menus don't have the raised border, nor do toolbar buttons, even when highlighted.) The menus themselves are on toolbars that can be dragged around, and items can even be dragged between the menu bar and other toolbars.
A commonly asked question is: can I get Office-style menus and toolbars with Windows Forms? Unfortunately, at the time this book went to press, the answer was no. Currently, the only two options are to recreate the behavior of Office menus and toolbars yourself, or to buy a third-party component to supply this behavior. Writing this behavior from scratch is nontrivial—you can get part of the way there by using owner-drawn menus, but you would still need to write a completely new toolbar.
For some reason, the development tools have always provided menu and toolbar support that is at least one generation behind the menu system used by the development environment itself. This is still true with Visual Studio .NET 2003—the IDE has Office-