Smart Clients

Craft A Rich UI For Your .NET App With Enhanced Windows Forms Support

Chris Sells and Michael Weinhardt

This article discusses:

  • What's new in Windows Forms controls
  • Settings and resource management
  • Layout, resizing, and scaling
  • Data binding
  • ClickOnce deployment
This article uses the following technologies:
Windows Forms, Visual Studio, .NET Framework 2.0

Contents

Windows Forms Projects
Code Separation
Improved Resource Management
Improved Setting Management
System.Windows.Forms.Form
Snap Lines, Margins, and Padding
Automatic Resizing and Scaling
TableLayoutPanel and FlowLayoutPanel
Controls and Components
MaskedTextBox Control
Web Browser
BackgroundWorker Component
AutoCompletion
Strip Controls
Strip Container
Data Binding
BindingSource
DataGridView
Drag and Drop Data Binding
ClickOnce Deployment
Publishing
Security
Where Are We?

Windows Forms 2.0 is far richer than any Windows application development platform that preceded it. You'll find improvements across the board, with a more dense and fully featured Microsoft® .NET Framework, tighter Visual Studio® integration with many new additional designers, a unified data binding model, and, the icing on the cake, ClickOnce for Web-style deployment.

Significant work has gone into the System.Windows.Forms namespace, the heart of the technology that comprises Windows® Forms. The usable surface area of the namespace, comprising public types (classes and enumerations), has increased by approximately 134 percent over the .NET Framework 1.1. There are 446 new public types; 113 existing types have been updated with new members and values; 218 types have been carried over from the original namespace; and no types have been removed. That's one major release. So major, in fact, that we don't have enough space to cover it all. However, Figure 1 gives you an overview. That's a lot of features! And they're all waiting for you when you create a new Windows Forms project.

Figure 1 New Features in Windows Forms 2.0

Feature Improvements
Forms Form class enhancements. Richer validation infrastructure. New form project wizards.
Layout SnapLines layout mode. Margin and padding support for automatic positioning and spacing. Specialized controls for Web-style flow and table layout, and for splitting. Automatic form resizing. Automatic form and control scaling across screen DPIs.
Drawing Native screen dumping support. GDI-based text rendering with the TextRenderer. Enhanced automatic and manual double buffering.
Printing Improved printing support across the gamut of printing-specific events, event arguments, enumerations, dialogs, and general printing classes.
Components/controls A host of new components and controls, including MaskedTextBox, WebBrowser, SoundPlayer, and Office 2003-style tool strip controls for menu bars, tool bars, status bars, and context menus. Smart tag support on a majority of controls and components for rapid configuration.
Design-time integration Several new design-time attributes. Updated design-time component initialization support. Smart tag integration for custom design-time components.
Resources Ability to both embed and link application resources. Exposure of application resources via strongly-typed wrapper classes. Default project-wide resource support for WinForms projects. Full right-to-left rendering support.
Applications Single-instance and splash screen support, via the Visual Basic runtime.
Settings Exposure of settings via strongly typed wrapper classes. Rich programmatic support for loading, updating, saving, and versioning settings. Safe settings persistence (for partial-trust code execution). Default project-wide settings support for Windows Forms projects.
Data binding Unification of heterogeneous data sources. Richer design-time support. DataGridView control with greater binding and grid UI capabilities. BindingNavigator for toolstrip-style (VCR-style) navigation. Tighter integration with Windows Forms validation.
Multithreaded user interfaces The BackgroundWorker component. Simplified asynchronous Web service method invocation.
ClickOnce deployment Automatic application publishing, delivery, and installation. Tight Visual Studio integration and configuration support. Trustworthy deployment. Smart client support.

Windows Forms Projects

Figure 2 Windows Forms Project Structure

Figure 2** Windows Forms Project Structure **

Whether you prefer C# or Visual Basic®, the first thing you'll notice when creating a new Windows Forms project is the new default project structure generated by the Visual Studio Windows Application project wizards, as shown in Figure 2. The updated structure represents several project enhancements we'll discuss.

Code Separation

One objective of the new default project structure is to remove code from the default Form1. The resulting trimmed-down implementation looks like this for C#:

// Form1.cs partial class Form1 : Form { public Form1() { InitializeComponent(); } }

Visual Basic spent a little more time at the code-trimming gym:

' Form1.vb Public Class Form1 End Class

You might be wondering where InitializeComponent went. In Windows Forms 2.0, designer-managed form code such as the InitializeComponent method is persisted to a new file, FormName.Designer.cs or FormName.Designer.vb. This separation, which is designed to keep developers and the Windows Forms designer from crossing swords, is enabled by new language support for partial classes in both C# and Visual Basic, as shown by the following code samples:

// Form1.cs (Developer-Managed) public partial class Form1 : Form { ... } // Form1.Designer.cs (Designer-Managed) partial class Form1 { ... void InitializeComponent() { ... } ... }

Here's the Visual Basic equivalent:

' Form1.vb (Developer-Managed) Public Class Form1 End Class ' Form1.Designer.vb (Designer-Managed) Partial Class Form1 Inherits System.Windows.Forms.Form ... Private Sub InitializeComponent() ... End Sub ... End Class

If you're a C# developer, you might also wonder where the wizard-generated static Main method has gone. Since Main is the application-scoped, rather than form-scoped, it's been moved to its own file, Program.cs:

// Program.cs static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { ... } }

Visual Basic projects are configured to launch Form1 on application startup by default. If necessary, a custom Shared Sub Main entry point can be used. The result of code separation is that developers can focus on writing just the code needed to address their specific problem.

Improved Resource Management

The IDE itself has been updated for easier Windows Forms 2.0 programming. The Visual Studio Resource Editor receives a much needed facelift, with the major benefits being improved management and the ability to see what your resources will actually look like, as shown in Figure 3.

Figure 3 Visual Studio Resource Editor

Figure 3** Visual Studio Resource Editor **

The Resource Editor now allows you to add new and existing files through a variety of mechanisms, including the dropdown list shown in Figure 3, pasting from the Clipboard, and dragging and dropping. Whichever mechanism you use, resources are automatically catalogued under one of these categories: Strings, Images, Icons, Text Files, and Sound Files. Another category, Other, exists for resource data like component-defined serialization of design-time data. To view each category, select the dropdown list in the upper-left of the Resource Editor. Each category adapts to the type of resource it contains to provide specialized views. For example, you can view all resource types other than strings via a Details, List, or Thumbnail view, just like in Windows Explorer.

Another important improvement is the ability to specify whether a resource is either embedded or linked. Embedded resources added to a project via the Properties Editor are stored in a project-wide resource (.resx) file. Linked resources (the default for resources other than strings) means Visual Studio references a file outside the project system, making it easier for different people to manage resource data (which you'd want for graphics and sound), while allowing developers to do what they do best: build applications. And Visual Studio comes through for developers on that front as well.

Consider what was previously required in Windows Forms 1.x to retrieve string resources from your code:

// Load string resource from project resource file Assembly assem = Assembly.GetExecutingAssembly(); ResourceManager resman = new ResourceManager("MyApp.Resource1", assem); string myStringResource = resman.GetString("MyString");

Now consider the simplified and strongly typed approach enabled by Windows Forms 2.0:

// Load strongly typed string resource string myString = Properties.Resources.MyString;

Windows Forms now generates a class, Resources (located within the ProjectName.Properties namespace), which exposes each resource via a strongly typed static (shared) property. Now, any resource type—including icons, images and sounds—can be easily retrieved from code as strings:

// Strongly typed resources of all kinds string myString = Properties.Resources.MyString; Icon myIcon = Properties.Resources.MyIcon; Image myImage = Properties.Resources.MyImage; UnmanagedMemoryStream mySound = Properties.Resources.MySound;

Any additional .resx files you add to your project will also cause strongly typed wrapper classes to be generated.

Improved Setting Management

There's a new Settings Editor, available from a project's property pages, which allows you to add settings to one of two scopes: application and user. Application settings, such as database connection strings and URLs, are permanent settings that don't change after an application is installed. User settings, such as those found in the Tools | Options menu, are default settings that users can change after installation. Figure 4 shows the Settings Editor in action.

Figure 4 Visual Studio Settings Editor

Figure 4** Visual Studio Settings Editor **

The Settings Editor deploys both application and user settings with an application's configuration file (ApplicationName.exe.config). And, like resources, Windows Forms generates a strongly typed wrapper class, located in the ProjectName.Properties namespace. Application settings are implemented as read-only properties while User settings are implemented as read/write properties. Both can be programmatically inspected or updated via a generated static (shared) Default property:

// Inspect an Application-scoped setting string myAppSetting = Properties.Settings.Default.MyApplicationSetting; // Update a User-scoped setting Properties.Settings.Default.MyUserSetting = "myNewUserSettingValue";

Since users expect their settings changes to be applied from one application session to the next, changed user settings need to be saved at the end of one session and reloaded at the beginning of another. While user and application settings are loaded automatically at the beginning of each session, you must manually save user settings at the end of a session by calling the Save method, exposed from the generated Settings class as shown here:

void OptionsForm_FormClosing(object sender, FormClosingEventArgs e) { // Save user settings for next time Properties.Settings.Default.Save(); }

Application settings are read-only, whereas user settings are not and must be saved to a file other than the application configuration file. For this reason, Windows Forms persists user settings to user.config, which is located in a Windows logo-compliant file system location that's tied to the user. The path to that file varies depending on certain conditions, such as whether roaming is enabled. The following location is used by standalone applications:

%InstallRoot%\Documents and Settings\UserName\ Local Settings\Application Data\ProductName\ ApplicationName.exe_Url_UrlHash\AssemblyVersionNumber

Sometimes, users change settings to values they are not happy with, but can't remember what the previous settings were. In this case, you can provide a mechanism to revert to the last saved settings by calling the Settings object's Reload method:

void reloadSettingsButton_Click(object sender, EventArgs e) { // Revert back to last saved user settings Properties.Settings.Default.Reload(); }

Second, if user settings are completely overcome, you can revert to an application's initially deployed settings: the values entered into the Settings Editor. Retrieving them requires calling the Settings object's Reset method:

void resetButton_Click(object sender, EventArgs e) { // Revert back to default installed user settings Properties.Settings.Default.Reset(); }

User settings are managed in such a way that, if the user.config file is deleted, the default values for those settings are loaded into the next application session.

System.Windows.Forms.Form

Whereas Visual Studio is the number-one tool for building Windows Forms applications, System.Windows.Forms.Form is the number-one class. As you would expect, this class has been updated, and now includes the addition of key new members listed in Figure 5. By far the most interesting of the new members are those dealing with layout.

Figure 5 Notable Enhancements to System.Windows.Forms.Form

Member Type Of Description
FormClosing, Events These succeed Closing and Closed as the events to handle FormClosed during form closure, as both offer more contextual detail, including what caused the shutdown, such as users, the Task Manager, Windows Shutdown, and so on. Closing and Closed still exist to support backwards compatibility.
ResizeBegin, ResizeEnd Events ResizeBegin and ResizeEnd offer more granularity around form resizing.
Shown Event Fired the first time a form is opened (while Activate is fired every time a form becomes active).
Validate Method Validates all controls on a form.
ValidateChildren Method Validates subsets of a form's child controls, as specified by the ValidationConstraints argument, including those that are enabled, selectable, visible, immediate children of the form, and can be tabbed to.
DrawToBitmap Method Allows you to screen dump an entire form, or a portion of it, to a bitmap.
AutoValidate Property AutoValidate allows you to specify the validation behavior of a form, using the AutoValidate enumeration, which provides four values for this purpose: Disable, EnableAllowFocusChange, EnablePreventFocusChange, and Inherit. Disable turns off control validation. EnableAllowFocusChange allows focus to be shifted from an invalid control while EnablePreventFocusChange prevents it. Inherit allows a control to take on the auto validation behavior of its host control or form.
RightToLeftLayout Property When you set the RightToLeft property to true, control text is swapped to the opposite side of where it was originally. When RightToLeftLayout is set to true, the controls themselves are swapped with respect to their layout on a form, as are form accoutrements like the system menu and minimize, maximize, and close buttons.

Snap Lines, Margins, and Padding

You can use snap lines to align controls as you drop them onto forms and drag them around. When dragged onto a form, snap lines manifest as one or more sticky lines that guide controls to alignment with other controls in close proximity, both horizontally and vertically, to common text baselines and text margins (see Figure 6).

Figure 6 Snapping Lines

Figure 6** Snapping Lines **

Besides being aligned to one another, controls need to be nicely spaced in relation to one another. While snap lines don't cater to spacing, two new properties found on Control do: Padding and Margin. Padding is the internal distance in pixels from the edge of a form or control's client area that child controls (and also things like text and images) can't intrude on. Margins are the external distances in pixels from control edges that other controls can't intrude on. As controls are dragged, a blue line is displayed between controls and the form when the distance between them is the sum of their Margins and Padding. Figure 7 shows Margins and Padding being used to determine when controls are correctly spaced. Both Padding and Margin properties can be specified for all edges at once or on an edge by edge basis.

Figure 7 Use of Margins and Padding

Figure 7** Use of Margins and Padding **

Automatic Resizing and Scaling

Since snap lines, margins, and padding are merely guides, they can be ignored, leading to the possibility that controls become either partially or fully hidden as they are moved or resized. You'll need to resize the container control to show the hidden parts of the resized or moved control, a tedious process when many controls are involved. Instead, you can use the AutoSize and AutoSizeMode properties. AutoSize is a Boolean property that, when set to true, instructs a control to resize automatically to fit its contents. The AutoSizeMode property tells the control how to resize, as specified by the AutoSizeMode (System.Windows.Forms) enumeration's GrowOnly and GrowAndShrink values.

GrowOnly specifies that a container should automatically resize if the new size of the contained control will be either the same size or bigger than its size. GrowAndShrink specifies that a container should both increase and decrease in size in response to contained controls resizing and moving, as illustrated in Figure 8.

Figure 8 Automatic Resizing with GrowAndShrink

Figure 8** Automatic Resizing with GrowAndShrink **

Automatic resizing is triggered when the edges of a control come close enough in proximity to the host container's right and bottom edges that their margins overlap. A variety of controls support AutoSize alone, or AutoSize and AutoSizeMode together. Some controls, like Forms, do implement both, but will only use them at run time. You'll need to experiment with each control in order to determine its level of automatic resizing support.

Besides being able to automatically resize to fit content, forms and controls are also able to automatically resize across DPI settings while maintaining consistent proportions with respect to size and position. Two key elements are required to maintain the same proportions, or scale, across multiple DPI settings. The first tells the form to automatically scale. The second tells the form what scale factor to apply to the size and position of the form and its controls. By default, forms automatically scale via their AutoScale property, which is set to true. The scale factor, specified by the AutoScaleMode property, can be one of the following values:

enum AutoScaleMode { None = 0, // Don't scale Font = 1, // Scale in relation to font size (default) Dpi = 2, // Scale in relation to dpi Inherit = 3 // Inherit container's AutoScaleMode }

The default is Font, meaning the scale factor, is based on the ratio between the average widths and heights of the default system font when the form was created and when the form executes. For example, if a form was created under Windows XP Normal fonts (96 DPI), the default font would be 8.25pt MS Sans Serif with an average width and height of 6x13. This information is stored in a form's AutoScaleDimensions property automatically by the Windows Forms Designer:

// AutoScalingForm.designer.cs partial class AutoScalingForm { ... void InitializeComponent() { ... this.AutoScaleDimensions = new SizeF(6F, 13F); ... } }

If the form were subsequently reopened or executed under Large fonts (120 DPI) where the default font will be 7.8pt MS Sans Serif, the average width and height of the font increases to 8x16. The form notices the difference between the AutoScaleDimensions and the current scale dimensions, and it adjusts the width, height, and position of its controls by the calculated difference. This keeps the general look of the form roughly the same, no matter what the system font settings are. The same behavior is consistent from within Visual Studio, too.

Whereas AutoSizeMode.Font causes scaling to be based on the difference of a font across DPIs, AutoSizeMode.Dpi causes scaling to be based purely on the difference across DPIs. Figure 9 compares the two modes.

Figure 9 AutoScaling from 96 DPI to 120 DPI

Figure 9** AutoScaling from 96 DPI to 120 DPI **

The real-world difference between AutoScaleMode.Font and AutoScaleMode.Dpi is that the former won't scale at the same rate as the latter since proportional fonts will scale differently than pure linear DPI scaling, especially from one language to the next. AutoScaleMode.Font is the default because it's the most robust option.

TableLayoutPanel and FlowLayoutPanel

While snap lines, margins, padding, automatic resizing, and automatic scaling comprise a useful layout toolbox, they can't easily support more complex scenarios where resizable dialogs host nontrivial numbers of controls. In anticipation of such scenarios, Windows Forms incorporates two new layout controls: TableLayoutPanel and FlowLayoutPanel.

TableLayoutPanel supports HTML-style table layout. You can define rows and columns that can be configured to automatically size in one of three ways:

  • AutoSize: automatically resizes to fit its contents
  • Percent: size is a percentage of the total height or width of a TableLayoutControl
  • Absolute: fixed size in pixels

Rows and columns can be merged and resized through the Windows Forms Designer. Each cell can contain just one control whose position within the cell is a function of docking and anchoring. Figure 10 shows an example of the TableLayoutPanel in action. It also shows both the OK and Cancel buttons hosted within a nested TableLayoutPanel, which is a useful technique when you need more than one control per cell.

Figure 10 TableLayoutPanel Control

Figure 10** TableLayoutPanel Control **

FlowLayoutPanel supports HTML-style flow layout. You can tell a FlowLayoutPanel the direction in which contained controls should be nudged during resizing by setting its FlowDirection property to one of four values: LeftToRight, TopDown, RightToLeft and BottomUp.

As with Web pages, a FlowLayoutPanel may be resized so that contained controls simply cannot be moved anymore, leaving them partially or fully covered by either vertical or horizontal edges of the FlowLayoutPanel, or both. In these situations, you can set the AutoScroll property to true to provide vertical and horizontal scroll bars if needed.

Controls and Components

Windows Forms 2.0 comes complete with a range of new controls and components that focus on filling holes in previous toolboxes, including MaskedTextBox, WebBrowser, and BackgroundWorker. Additionally, there are a variety of improvements across the control and component libraries, including the ability for common controls to visually adapt to the current Windows theme on the fly, and designer support for smart tags to enable more rapid and focused configurations for developers.

MaskedTextBox Control

The MaskedTextBox control is designed to provide a more informative and accurate data entry experience by guiding users with hints as to the type and shape of data to be entered using a mask (see Figure 11). There are a lot of mask characters; if you need help building and testing a mask, you can open the MaskedTextBox control's Input Mask Editor from the Properties window.

Figure 11 Data Types for MaskedTextBox

Mask Description Data Format Validating Type
Numeric (5 digits) 12345 Int32
Phone number (574) 555-0123 (None)
Short date 12/11/2003 DateTime
Short date and time (US) 12/11/2003 11:20 DateTime
Time (European/Military) 23:20 DateTime
Zip code 98052-6399 (None)

Figure 12 MaskedTextBox

Figure 12** MaskedTextBox **

By default, non-mask characters, such as parentheses, hyphens, and spaces, are treated as literals and are shown at run time to describe the shape of the required data, while all mask characters are replaced by a prompt character at run time (underscore by default, and only shown when the MaskedTextBox has the focus, as shown in Figure 12). MaskedTextBox implements a wide variety of properties, the most interesting of which are listed in Figure 13. MaskedTextBox is a highly configurable control you should consider when giving users a more informed data entry experience.

Figure 13 Key MaskedTextBox Properties

Property Description
HidePromptOnLeave True by default but, if set to False, ensures prompt characters are always visible.
PromptChar Used to change the prompt character. Underscore by default.
AllowPromptAsInput In some cases, your prompt character may also be a valid value, and setting AllowPromptAsInput to True allows this where neither can be reasonably changed.
BeepOnError Beeps whenever an invalid character is entered.
CutCopyMaskFormat Specifies how masked text box data is copied. Is one of four MaskFormat enumeration values, including ExcludePromptAndLiterals, IncludePrompt, IncludeLiterals, and IncludePromptAndLiterals.

Web Browser

Whereas Windows Forms applications have always been able to support Web browsing using COM controls via interop, the programming experience was a little messy. The new Web Browser control, however, provides a managed way to easily augment Windows Forms applications with Web browsing capabilities, as shown in Figure 14.

Figure 14 WebBrowser Control in Action

Figure 14** WebBrowser Control in Action **

Navigating to a URL is as simple as invoking the WebBrowser's Navigate method:

void goButton_Click(object sender, EventArgs e) { // Navigate to URL this.webBrowser.Navigate(this.urlTextBox.Text); }

When the WebControl has navigated to a new page, it fires the Navigated event before it begins downloading the page. WebControl also fires the ProgressChanged event by which you can monitor page download progress. And, of course, WebBrowser provides methods to handle the several standard navigation options found in any browser:

this.webBrowser.GoBack(); // Navigate to previous page in history this.webBrowser.GoForward(); // Navigate to next page in history this.webBrowser.Stop(); // Stop loading of the current page this.webBrowser.Refresh(); // Reload the current page this.webBrowser.GoHome(); // Navigate to home page

BackgroundWorker Component

Windows Forms applications often need to perform long background operations such as searching. The solution is to use multithreading support in .NET to spin off worker threads to execute the long-running operations asynchronously, which allows the main UI thread to continue servicing user requests. But coding worker threads can be hard and time-consuming.

In Windows Forms 2.0, however, you can use BackgroundWorker, which encapsulates the complexities of worker thread creation and management into a single component that you can drag onto a form in Visual Studio. Invoking BackgroundWorker.RunWorkerAsync causes a worker thread to raise the BackgroundWorker.DoWork event you handle to execute your long-running operation code. RunWorkerAsync and DoWork are shown in the code in Figure 15.

Figure 15 Working in the Background

public partial class TaskForm : Form { // RUN ON UI THREAD void startOperationButton_Click(object sender, EventArgs e) { // Create data to pass to worker thread MyData data = new MyData(); ... // Initiate worker thread this.backgroundWorker.RunWorkerAsync(data); } // RUN ON WORKER THREAD void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { // Extract data passed from UI thread MyData data = (MyData)e.Argument; // Execute long running, asynchronous operation ... } }

BackgroundWorker ensures that data you pass between the UI and worker threads is done so in a thread-safe manner. BackgroundWorker also supports progress reporting and cancellation, and, because it's a component, it allows you to configure this functionality from the designer.

AutoCompletion

One improvement that applies to several controls is auto-completion. This is implemented on ComboBox, TextBox, ToolStripComboBox, and ToolStripTextBox. It comprises three properties: AutoCompleteMode, AutoCompleteSource, and AutoCompleteCustomSource. AutoCompleteMode allows you to set the auto-completion style from an enumeration of the same name:

enum AutoCompleteMode { None = 0, // No auto-completion (default) Suggest = 1, // Possible matches chosen from drop-down list Append = 2, // Possible matches appended to text while typing SuggestAppend = 3 // AutoSuggest and AutoAppend combined }

An option other than "None" requires you to set the AutoCompleteSource property to one of several system auto-completion sources specified by the AutoCompleteSource enumeration:

enum AutoCompleteSource { FileSystem = 1, // File system HistoryList = 2, // All URLs from History list RecentlyUsedList = 4 // All URLs from Recently Used list AllUrl = 6, // HistoryList + RecentlyUsedList AllSystemSources = 7, // FileSystem + AllURL FileSystemDirectories = 0x20, // File system folders CustomSource = 0x40, // AutoCompleteCustomSource None = 0x80, // No source (default) ListItems = 0x100 // Items in control list (combo boxes only) }

Choosing CustomSource instructs the ComboBox that you will provide auto-completion options from a collection of items stored in the AutoCompleteCustomSource property. ListItems specifies the source to be the items stored in the ComboBox's List property.

Strip Controls

Deserving special mention due to their sheer coolness are the strip controls. MenuStrip, ToolStrip, StatusStrip, and ContextMenuStrip add a contemporary flavor to your user interfaces, as illustrated in Figure 16.

Figure 16 Strip Controls

Figure 16** Strip Controls **

The new strip controls succeed MainMenu, ToolBar, StatusBar, and ContextMenu (retained in Windows Forms 2.0 for backwards compatibility) and improve on them in several ways, including:

  • A consistent API to all strip controls
  • Improved design-time experience
  • Dragging between form edges
  • Office 2003 and Windows Themes sensitivity
  • Can host a rich set of child controls, including dropdown lists, labels, menus, and textboxes
  • Simplified custom painting support
  • Integration with the settings system
  • Form integration with the MainMenuStrip property, and control integration with the ContextMenuStrip property

Strip controls offer a large degree of design-time support, the most important of which is to simplify the addition of items to each strip control. The items that can be added to a strip control depend on the purpose of the strip control, as outlined in Figure 17.

Figure 17 Strip Control Items and Their Hosts

Strip Control Designer-Allowed Strip Item Controls
MenuStrip ToolStripMenuItem (for both top menu and sub menu items)
ToolStripComboBox
ToolStripTextBox
ToolStripSeparator (for sub menus)
ContextMenuStrip Same as MenuStrip
ToolStrip ToolStripButton
ToolStripComboBox
ToolStripSplitButton
ToolStripLabel
ToolStripSeparator
ToolStripDropDownButton
ToolStripTextBox
ToolStripProgressBar
StatusStrip ToolStripStatusLabel
ToolStripProgressBar
ToolStripDropDownButton
ToolStripSplitButton

Strip control items can be added, updated, and deleted via the Properties window, with smart tags, or visually from the design surface. Both MenuStrip and ToolStrip provide an "Insert Standard Items" option to pre-populate the controls with items for typical commands such as Open, Save, Save As, Cut, Copy, and Paste.

The strip control Properties window and smart tag support enable a variety of other interesting configurations, the most important of which are controlled by the properties listed in Figure 18. Apart from the standard properties you would typically find on controls, such as Enabled, Visible, Checked, and BorderStyle, strip controls offer some additional properties, outlined in Figure 19.

Figure 19 Key Tool Strip Item Control Properties

Property Description
Alignment Determines which end of a tool strip control a tool strip item control will align to, either Left or Right.
DisplayStyle Specifies what elements to display, including None, Text, Image, ImageAndText.
ImageScaling Specifies how an image is rendered, either ShrinkToFit or None.
Overflow Determines how each strip item control responds to overflow. Can be either Never, Always, or AsNeeded, which leaves the decision up to the host strip control.
TextImageRelation Sets the position of text in relation to an image. Applies when DisplayStyle is ImageAndText.

Figure 18 Key Strip Control Property Configurations

Property Description
AllowItemReorder Like with Office 2003 toolbars, users can reposition strip items by setting this property to True. Also like with Office 2003, the user needs to press Alt before repositioning. (Excluding ContextMenuStrip.)
CanOverflow When the form becomes narrower or shorter than a strip control, this option specifies how to visually represent tool strip items hidden by the overlap; either hidden if False or accessible via a dropdown at the end of the strip control if True.
Dock Specifies the form edge to line up against or fill.
GripStyle Specifies whether a MenuStrip or ToolStrip displays a grip, allowing it to be repositioned.
Renderer Sets a custom ToolStripRenderer implementation to provide non-default tool strip UIs. Causes RenderMode to be set to Custom.
RenderMode Strip controls support four render modes.
System: rendered with colors from the system palette. Professional: rendered according to the current Windows Color Scheme, being either Blue, Olive Green, or Silver. ManagerRenderMode: rendered using the Windows Theme sensitive ToolStripRenderer—and is the default.
Custom: can't be set explicitly—see Renderer property.
ShowItemToolTips Sets whether strip items can also display tooltips. (False for MenuStrip and ContextMenuStrip.)
SizingGrip Sets whether to hide or show the form sizing grip. (StatusStrip only.)

Strip Container

One of the key features of the strip control suite is the ability to drag them from one edge of a form to another. While strip controls are docked to form edges by default, docking doesn't provide the smarts to support dragging. Instead, this behavior is added to a form with a ToolStripContainer control, shown in Figure 20.

Figure 20 ToolStripContainer Control

Figure 20** ToolStripContainer Control **

Because ToolStripContainer is a container control that provides form-wide strip control semantics, it needs to be added to a form before any other controls. Controls are then added to its content panel, while strip controls are added to one of four special panels. Each panel can be expanded or collapsed to accommodate the strip controls you'd like against each form edge. You can also hide/show panels as needed by setting the ToolStripContainer's TopToolStripPanelVisible, RightToolStripPanelVisible, BottomToolStripPanelVisible, and LeftToolStripPanelVisible Boolean properties.

At run time, you can drag strip controls between the edges of the form for which panels are visible. Only strip controls that have a drag grip can be dragged. And if two or more tool strip controls reside in the same tool strip panel, they can be repositioned amongst themselves as required by the user. Since tool strips can be moved to new positions by users at run time, users will expect them to be in those positions from one application session to the next. For this, you use the ToolStripManager class (from System.Windows.Forms), which nicely implements the static (shared) LoadSettings and SaveSettings methods.

Data Binding

In Windows Forms 2.0, data binding is much richer than before thanks to the new BindingSource component whose primary role is to upgrade non-data binding-savvy data sources with richer data-binding capabilities. This enables the unification of disparate data sources and, in addition, facilitates the creation of a single client code pattern for any type of data source.

Figure 21 Data Sources

Figure 21** Data Sources **

A data source can be easily added to a project using the Data Source Configuration Wizard (Data | Add New Data Source). From there, you can create data sources for databases, Web services, and objects. If you create a data source from a database, a new strongly typed DataSet is added to your project and can be viewed from the new Data Sources window (Tools | Data | Show Data Sources), shown in Figure 21.

The Data Sources window provides tool strip items that allow you to add new data sources and, if a data source is a strongly typed DataSet, edit, reconfigure, or refresh them. When dropped onto a form, controls like DataGridView will automatically prompt you to select a data source or create a new one.

BindingSource

When you think "data source," you are likely to think of the most popular type: the typed DataSet. But data sources come in many shapes and sizes, including tables, XML, and .NET-based objects. All of these could be bound to in Windows Forms 1.x, with differing levels of data binding integration. This forced developers to spend a nontrivial amount of time updating their data sources to achieve higher levels of data binding integration by implementing IBindingList. The Windows Forms 2.0 BindingSource component addresses this problem by being able to consume any list type and reexposing these as IBindingList list data source implementations. Additionally, item types can be handed to the BindingSource component, which turns them into an IBindingList implementation for you.

To configure a BindingSource to consume the desired data source, drop one onto your form and set its DataSource and DataMember properties appropriately. Here's an example of BindingSource consuming a typed DataSet:

public partial class DataBindingForm : Form { public DataBindingForm() { ... // Consume a type data set this.bindingSource.DataSource = this.northwindDataSet; this.bindingSource.DataMember = "Employees"; } }

The BindingSource component now exposes a strongly typed DataSet as a data source against which controls can bind.

DataGridView

The Windows Forms team took the opportunity to respond to community feedback on the DataGrid by constructing a wholly new grid control, System.Windows.Forms.DataGridView. (DataGrid still exists for navigating and editing hierarchical data.)

One striking difference between DataGrid and DataGridView is the latter's object model, which has been abstracted into a natural grid structure composed from columns, rows, and cells, illustrated by Figure 22. This natural grid structure allows developers to quickly and logically drill down into a ton of intuitively located functionality, including:

  • Rich UI customization support through styles, formatting, layout, and item selection
  • The ability to natively display a broader variety of data types than the DataGrid, including images
  • Nifty features like frozen columns and run-time column reordering
  • More than 100 events for granular control over navigation, editing, validation, custom painting, and error handling

Figure 22 DataGridView Object Model

Figure 22** DataGridView Object Model **

One of the new capabilities is row selection on cell click, which is configured via the DataGridView's SelectionMode property. Of course, no control can be everything to everyone. When they have to, developers can lean on extensibility to incorporate custom features. The DataGridView infrastructure offers a variety of cell, row and column base implementations you can derive from and plug in, including DataGridViewColumn and DataGridViewCell. All this makes the DataGridView a much more compelling grid-style control than the DataGrid.

The most common way to fill a DataGridView is to bind it to a data source, which can be achieved by setting its DataSource property to a BindingSource, as shown in Figure 23.

Figure 23 Binding the DataGridView to a BindingSource

Figure 23** Binding the DataGridView to a BindingSource **

While DataGridView displays multiple items, you sometimes want to view one item at a time. In this case, you can just as easily bind controls like the TextBox to a BindingSource. But when you view one item at a time, you need a way for users to navigate between items. Such support is typically provided by a VCR-style control. Rather than creating your own, you can drag a BindingNavigator onto a form and bind it to the same BindingSource your controls are bound to. BindingNavigator also provides current item and total item count information, as well as support for both adding and removing items to and from the data source.

Drag and Drop Data Binding

Dragging and dropping controls and components and writing code to hook them up seems contrary to the idea that data binding has improved productivity. Rather than manually drag and drop and then configure your UI, you can instead drag and drop a data source from the Data Sources Window onto a form and have the Windows Forms Designer create and configure a bound UI for you.

When you drag and drop a data source, the Windows Forms Designer:

  • Adds a BindingSource for that data source
  • Adds a strongly typed DataSet and table adapter if required
  • Adds the required controls bound to the BindingSource, providing them with reasonable names (apart from DataGridView columns)
  • Adds a BindingNavigator bound to the BindingSource

You can also configure whether the dropped data source creates a DataGridView-UI or Details-UI and in either case which controls are generated to suit.

ClickOnce Deployment

Eventually, an app needs to be deployed. While setup apps or Microsoft Installer (MSI) files are fine deployment technologies, they do need to be distributed to and executed on a client, and the resulting installation needs to be kept up to date. This can be tough. Web applications have a great deployment model: users are kept up to date with the latest version without having to do a thing.

Good technologies borrow from other technologies; great technologies steal wholeheartedly. Windows Forms 1.x came with a technology known as "No-Touch Deployment" (NTD), which borrowed from the Web deployment model and allowed Windows Forms applications to be deployed from either a URL or a UNC file path and executed within a sandbox on the client machine controlled with code access security (CAS). In Windows Forms 2.0, NTD has evolved into ClickOnce Deployment, offering a Web-style deployment model to Windows Forms applications. ClickOnce offers the following capabilities:

•Rich configuration for the creation, publishing, and management of deployed applications

  • Multiple publish locations, including Web servers, FTP servers, file shares, and media such as CD and DVD
  • Hyperlink-style application launching
  • Two install modes, online and online/offline; the latter allowing ClickOnce applications to be launched without a network connection once cached on the user's machine
  • Control over the level of integration with the client, including the Start menu and Add/Remove Programs control panel
  • Selection of installation prerequisites, such as the .NET Framework 2.0 (from the Prerequisites button)
  • File and assembly dependency management
  • The setting of various publishing details including publisher details, a support Web page, and a deployment Web page, which ClickOnce can automatically generate
  • Using a publish version number, versioning policies for a variety of scenarios can be created
  • Trustworthy deployment and execution model built around code signing and CAS that is completely user-driven
  • Complete integration with Visual Studio

At design time, ClickOnce deployment can be configured from Visual Studio via the Publish tab of a project's property pages, shown in Figure 24. The confluence of these various configurations is applied when an application is published.

Figure 24 Configuring ClickOnce Deployment

Figure 24** Configuring ClickOnce Deployment **

Publishing

The easiest way to publish an application is to right-click your project in Solution Explorer and choose Publish, which opens the Publish Wizard to collect various details from you, including publish location and install mode.

When an application is published, Visual Studio and ClickOnce prepare an installation package based on your configurations and copy it to the publish location. ClickOnce generates a folder with a name that combines the application's name and published version number. This folder contains the main application assembly and any other dependent files. Each will be suffixed with ".deploy" when published to a Web server that has a policy of not allowing common executable file types (.exe, .dll) to be uploaded. To store the files that comprise an installation package, ClickOnce generates an application manifest (.manifest), which also captures the various configurations you made from Visual Studio.

Because there can be more than one published application version, users need a way to determine which version to download. For this, ClickOnce generates a deployment manifest (.application) and adds it to the published app's root, as shown in Figure 25.

Figure 25 ClickOnce Published Application

Figure 25** ClickOnce Published Application **

Two deployment manifests are generated, one for the latest published version and one for a specific version. In the root, a setup application is created for users to execute if they lack any prerequisites, such as the .NET Framework 2.0, and a default Web page that users can browse to and launch a published application from. To launch the application, users click the Install button, which is a hyperlink to the application manifest for the latest version.

Security

When an application is launched, ClickOnce first downloads the manifests to determine whether or not an application is safe to download and execute without user intervention. If a security issue is discovered, it is raised via the Security Warning dialog. If there are any security issues, users are given the option to continue installing an application or bail. To help them make that decision, users can view the security issues in detail by clicking the "More Information" link.

ClickOnce divides its warnings into four categories: Publisher, Machine Access, Installation, and Location. Publisher refers to who published the application. For ClickOnce to deem a publisher as safe, that publisher will need to sign their code using a digital certificate issued by a certification authority (CA) such as Verisign. You sign your application from the Signing tab of a project's property pages in Visual Studio. This tab allows you to import a certificate from a certificate store or file, create a test certificate, specify a timestamp server for certificate expiration, and sign or delay-sign your assembly.

Machine access refers to the permissions required by an application to execute on a client machine. A ClickOnce application's permissions are managed by .NET CAS, which wraps executing .NET-targeted applications in a security sandbox that allows only the permissions granted to those applications. ClickOnce flags a security warning when the required permissions exceed those allowed for applications launched from the same zone from which the application is being launched. When a user chooses to install an application with excessive permission requirements, CAS grants those permissions to the application, a process known as permission elevation. It's possible to manage permission requirements for an application from the Security tab of a project's property pages, shown in Figure 26.

Figure 26 ClickOnce Security Settings

Figure 26** ClickOnce Security Settings **

The Security tab allows you to specify full or partial trust and, in the case of the latter, choose the subset of required permissions manually or have them calculated for you. You can also choose the default permissions for the zone you are targeting and change them as required. You can debug your app as if it were deployed from the specified zone and is restricted to the specified permissions.

Where Are We?

We covered a lot of ground, going over the key new features of Windows Forms 2.0. It's hard not to get excited, especially when you consider that a year's worth of MSDN®Magazine wouldn't have enough space to cover all the new features in detail. However, the bigger and meaner .NET Framework, new controls and components, improved data binding, ClickOnce deployment, and richer integration with Visual Studio we've shown you are certainly good places to start exploring. Once familiar with Windows Forms 2.0, you'll find yourself building Windows Forms applications with more functionality in less time then ever, using a technology that will be the flagship Windows application development platform for many years to come.

Chris Sells is a program manager for the Connected Systems Division at Microsoft where he is working on next-gen application development techniques. More info about Chris and his various projects can be found at www.sellsbrothers.com.

Michael Weinhardt is currently co-updating Windows Forms Programming in C# (by Chris Sells, Addison-Wesley Professional, 2003) and writes a monthly column for MSDN Online called Wonders of Windows Forms.