[ Editor's Update - 1/20/2006: This article refers to a beta version of Visual Studio 2005. An updated version of the article, reflecting features found in the final release of Visual Studio 2005, can be found at Smart Clients: Craft A Rich UI For Your .NET App With Enhanced Windows Forms Support.]

Draft a Rich UI

Ground Rules for Building Enhanced Windows Forms Support into Your .NET App

Chris Sells and Michael Weinhardt

This article is based on prerelease versions of Visual Studio 2005 and the .NET Framework 2.0. All information contained herein is subject to change.

This article discusses:
  • Productivity-focused updates in Visual Studio 2005
  • Resource and settings management improvements
  • Flexible control layout and new strip controls
  • Data binding
This article uses the following technologies:
.NET Framework 2.0, Visual Studio 2005

Contents

Project Configuration
Improved Resource Management
Improved Settings Management
System.Windows.Forms.Form
Form and Control Layout
Strip Controls
ToolStripContainer
Strip Control Settings Management
MaskedTextBox Control
Data Binding
Binding to a Data Source
New Data-Bound Components
Where Are We?

Since we last looked at Windows® Forms 2.0 in May 2004, Microsoft has renamed, improved, and added a considerable number of features. The features discussed in this article are from the December 2004 Community Technology Preview, so you can definitely expect some things to change in the final release. (For our first article on Windows Forms, see Craft a Rich UI for Your .NET App with Enhanced Windows Forms Support.)

A Windows Forms project is the gateway to exploring all the new features, and even the gate has been updated in the latest drop. The new default template-generated layout is shown in Figure 1.

Figure 1 Default Generated Windows Forms Projects

Figure 1** Default Generated Windows Forms Projects **

Much of the new project layout is focused on removing unnecessary code from the default wizard-generated forms, leaving a trimmed-down version that 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

If you've used previous versions of Visual Studio®, you might be wondering where the InitializeComponent implementation went. All Windows Forms designer-managed form code such as the InitializeComponent implementation has been migrated to a new file, FormName.Designer.cs or FormName.Designer.vb, as shown in Figure 1. To split the class across two physical files, the designer takes advantage of new language support for partial classes:

' Form1.vb (Developer-Managed)
Public Class Form1
End Class

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

Here's the C# equivalent:

// Form1.cs (Developer-Managed)
partial class Form1 : Form {...}

// Form1.Designer.cs (Designer-Managed)
partial class Form1 {
  ...
  private void InitializeComponent() {...}
  ...
} 

If you're used to C#, you might also wonder where the application entry point (static Main method) has gone. Because Main isn't related to any specific form, it's also been moved to its own file, Program.cs, as shown here:

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

By default, Visual Basic 2005 projects are configured to launch Form1 on application startup. If necessary, a custom Shared Sub Main can be specified as the application entry point. For developers, this code separation means you only have to write the code needed to address the specific problem. From a Windows Forms Designer point of view, separating InitializeComponent protects you from inadvertently tampering with it and potentially causing irreparable damage to your form.

Project Configuration

Windows Application projects also include new folders to manage project configuration. They are My Project for Visual Basic and Configuration for C#. Duncan Mackenzie covers My Project in his detailed article at Navigate the .NET Framework and Your Projects with "My", so we'll just take a look at the C# side of things here. Figure 2 shows the result of double-clicking a project's Configuration folder.

Figure 2 C# Project Property Editor

Most of the configuration settings from previous versions of Visual Studio can be found here, although Resources and Settings are new. Exposing project configuration via a designer-managed editor instead of a modal dialog makes them more accessible; project configuration can be kept open constantly and accessed with only a single click of a Visual Studio 2005 file tab.

Improved Resource Management

A good deal more has happened to project resources than simply exposing them via a tab. For starters, the Resource Designer has been given a much needed facelift, the major benefits being improved management and the WYSIWYG ability to see what your resources look like at design time, as illustrated in Figure 3.

Figure 3 Visual Studio 2005 Resource Editor

Figure 3** Visual Studio 2005 Resource Editor **

The new Resource Designer 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. You can even drag strings from sources like Microsoft Word, saving you extra typing where string data already exists.

Whichever mechanism you use to add resources, they are automatically added to one of several categories, including Strings, Images, Icons, Text Files and Sound Files. Another category, Other, holds extra resource data such as component-defined serialization of design-time data. You can view each category by changing the value of the aptly named Categories selection. Each category offers more granular views. For example, you can view all resource types other than strings through Details, List, or Thumbnail view.

Beneath the surface, the Resource Designer persists resource data to the new default Resources resource (.resx) file contained within the Configuration project folder, and works hard to make your resource programming experience as simple as resource management is now. Consider what was previously required to retrieve a string resource 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 Visual Studio 2005:

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

The Resource Designer exposes every resource you add to your project's resources as a strongly typed, static (shared) property from a resource editor-generated managed class called Resources that lives within the ProjectName.Configuration namespace. These properties are generated after either the project is rebuilt or after you run the custom tool associated with the .resx file to generate the class: ResXFileCodeGenerator. Now any type of resource including icons, images, and sounds is as easy to retrieve as a string:

// Strongly typed resources of all kinds
Icon icon = Configuration.Resources.MyIcon;
Image image = Configuration.Resources.MyImage;
MemoryStream sound = new MemoryStream(Configuration.Resources.MySound);

Currently, only a default Windows Forms project's resource file generates a strongly typed resource class by default. If you want the same support for additional .resx files, you'll need to set their Custom Tool property to ResXFileCodeGenerator.

Improved Settings Management

Like resources, settings have a custom editor that allows you to add typed settings to one of two scopes: read/write user settings and read-only application settings. User settings can change frequently, while application settings, like database connection strings, are expected not to change once an application is deployed. Application settings are persisted to an application's configuration file (applicationName.exe.config). Figure 4 shows how you can use the Settings Designer to set both user and application settings.

Figure 4 Visual Studio 2005 Settings Editor

Figure 4** Visual Studio 2005 Settings Editor **

The Settings Designer generates a Settings class (located in the ProjectName.Configuration namespace), from which it exposes each setting as a per-instance property of the type specified. Application settings are exposed as read-only properties while User settings are exposed as read/write properties. Either way, properties can be programmatically inspected or updated via a generated static (shared) Value property:

// Inspect an Application-scoped setting
string appSetting = Configuration.Settings.Default.MyAppSetting;

// Update a User-scoped setting
Configuration.Settings.Default.MyUserSetting = "myNewUserSetting";

This support offers the same great benefits you would get by using strongly typed resources, especially when ad hoc settings processing is all you need.

Since users expect their settings changes to be saved from one application session to the next, settings need to be loaded at the beginning of each new session and saved at the end of each. Half of this job is taken care of for you: application and user settings are automatically loaded when first used in a new session. To save them at the end of each session, you have to make a single call to the Save method, which is exposed to your code indirectly via the Settings class:

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

A suitable location for this code would be the FormClosing event handler. User settings are persisted to a Windows Logo-compliant location within the file system on a per user basis in a file named user.config, where user is the current user's profile name. On a typical system, here's the path to that file:

c:\documents and settings\username\Local 
Settings\Application Data\company name\product 
name_hash\product version\

Sometimes users change settings to values they are not happy with and then can't remember what the previous defaults were. Fortunately, there are two simple recovery options. First, you can provide a mechanism for users to revert to the last saved settings by calling the Settings object's Reload method, like so:

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

This loads the settings from the same persistent store used when the application was first started. If user settings are changed beyond all recognition, you can revert to the default user settings, which are the initial values entered into the Settings Designer. To retrieve them, simply call the Settings object's Reset method:

private void resetButton_Click(object sender, EventArgs e) {
  // Revert back to default installed user settings
  Configuration.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, which is the same as calling the Reset method. The settings subsystem comes with more exotic capabilities, including upgrade support, settings profiles, and even the ability to create custom settings providers—a feature that would allow you to save user settings to a Web service, for example.

System.Windows.Forms.Form

It's also worth your time to explore the full gamut of enhancements to System.Windows.Forms.Form, the number one class in Windows Forms app development. The changes to System.Windows.Forms.Form have been made in accordance with the prime objective of the .NET Framework 2.0: productivity. Figure 5 lists key new members that will simplify your life. Of particular interest are the enhancements to layout capabilities.

Figure 5 System.Windows.Forms.Form Key Enhancements

Member Type Description
Flash, StopFlash Methods Flashes your form's taskbar button, window title bar, and window StopFlash border. Inactive forms flash to notify the user that something has happened. By default, calling Form.Activate will flash both taskbar button and window title three times.
ValidateAll Method Validates all controls within a scope specified by the ValidateFlags enum, including All, Enabled, ImmediateChildren, Selectable, TabStop, and Visible. Calling ValidateAll passing in a ValidateFlags value defaults to Selectable.
AutoValidate Property Can be one of three values: Yes (default), No, or Inherits. No prevents any controls with CausesValidation set to true from firing their Validating and Validated events, which avoids focus being retained in an invalid control.
FormClosing, FormClosed Events Use instead of Closing and Closed when a form is closed; both offer more detailed information.
ResizeBegin, ResizeEnd Events If handling the Resize event is not granular enough, ResizeBegin and ResizeEnd should give more flexibility.

Form and Control Layout

Both System.Windows.Forms.Form and the Windows Forms Designer have been enhanced to offer richer support for form and control layout management. The whole process has been simplified dramatically.

Snap-lines, Beta 1 Style In our previous article, we showed how snap-lines simplify the task of aligning controls with horizontal and vertical edges; the designer redlines snap-lines with a third snap-to feature that helps align controls to common text baselines. Figure 6 shows top-edge, text baseline, and bottom-edge snap-lines in action.

Figure 6 Alignment

Figure 6** Alignment **

Padding and Margins Snap-lines allow you to quickly align your controls horizontally and vertically as you drag them around a form. Besides being aligned to one another, controls also need to be nicely spaced out. That's the job of two new properties: 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 text, images, and so on) can't intrude on. A margin is the external distance in pixels from the edge of a control that other controls can't intrude on. When you drag controls around a form, the Windows Forms Designer will display a dotted line between controls and the form when the distance between them is the sum of both their Margins and Padding (where relevant). Figure 6 shows the dotted line between Label and TextBox controls. Figure 7 shows how margins and padding are used to determine when controls are correctly spaced. Both Padding and Margin properties can be specified at once for all edges, or specified edge by edge.

Figure 7 Margins and Padding

Figure 7** Margins and Padding **

Complex Layout Scenarios For more complex layout scenarios, such as resizable dialogs with nontrivial numbers of controls, you'll need an advanced layout engine, an infrastructure for building specialized layout controls to handle more elaborate layout needs. Two layout control implementations come with Windows Forms 2.0, TableLayoutPanel and FlowLayoutPanel, both of which borrow from HTML-style layout capabilities. Both are panel-like controls designed to host other controls while simultaneously applying their particular layouts at both design time and run time.

TableLayoutPanel TableLayoutPanel allows you to define rows and columns that can be configured to size automatically in one of three ways: AutoSize, Percent, and Absolute. Rows and columns can also be merged and physically resized through the Windows Forms Designer. Each cell can only contain one control whose position within the cell is determined by docking and anchoring. Figure 8 shows an example of how the TableLayoutPanel might be used.

Figure 8 TableLayoutPanel Control

Figure 8** TableLayoutPanel Control **

Figure 8 also shows both the OK and Cancel buttons hosted in a nested TableLayoutPanel. Since TableLayoutPanel can host only a single control in each cell, you might find nested tables a useful technique. Alternatively, you could utilize TableLayoutPanel's support for merged columns and rows.

FlowLayoutPanel If tabular layout is not what you're after, the FlowLayoutPanel might be more suitable, especially when you want a form and its controls to resize the way HTML Web pages do. You can tell a FlowLayoutPanel the direction in which the controls should be moved during form resize by setting its FlowDirection property to one of four values: LeftToRight, TopDown, RightToLeft, or BottomUp.

As with Web pages, a FlowLayoutPanel may be resized to be so small that controls simply cannot be moved any more, leaving them partially or fully covered by either vertical or horizontal edges of the FlowLayoutPanel, or both. Setting its AutoScroll property to True provides vertical and horizontal scrollbars as needed.

Strip Controls

Besides the layout panels, some of the new controls you saw in our previous article have undergone significant enhancements. One of the most significant is reminiscent of the movie Gremlins; someone at Microsoft obviously fed the WinBar after midnight because it has since multiplied into a complete suite of "strip" controls, including MenuStrip, ToolStrip, StatusStrip, and ContextMenuStrip (see Figure 9).

Figure 9 Strip Controls

Figure 9** Strip Controls **

The new strip controls improve on MainMenu, ToolBar, StatusBar, and ContextMenu in several key ways, including:

  • A consistent API to all strip controls
  • Improved design-time experience
  • Allowing adjacent strip controls to be repositioned with respect to one another, as well as repositioned to the top, right, bottom, and left of the host form's client area
  • Contemporary look of Office 2003 and Windows themes
  • Ability to host a rich set of child controls, such as dropdown lists, labels, menus, and textboxes
  • Rendering support that simplifies custom painting coding

While MainMenu, ToolBar, StatusBar, and ContextMenu are not included by default in the Visual Studio Toolbox, they are still included in the .NET Framework, primarily for backwards compatibility. Of course, the strip controls are located on the Toolbox so you can easily drag them onto your form. Through the Designer, you can add a variety of controls to each strip control (see Figure 10).

Figure 10 Controls Hosted by Strip Control

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

Strip controls offer a number of flexible configuration options. Both strip controls and strip item controls can be wholly configured from the Property Browser, while smart tags support configuration of the key properties for each specific control. If that's not enough, you can add, update, and delete strip items on the visual design surface directly, or from an Edit Items dialog, which can also be accessed from both Property Browser and smart tags, as appropriate.

Both MenuStrip and ToolStrip provide an Insert Standard Items option to prepopulate strip items for typical commands such as Open, Save, Save As, Cut, Copy, and Paste. Interesting configuration options you can apply are listed in Figure 11.

Figure 11 Key Strip Control Property Configurations

Property Description
AllowItemReorder Users can reposition strip items by setting this property to True. The user needs to press Alt before repositioning (not for ContextMenuStrip).
ShowItemToolTips Sets whether strip items can also display tool tips (not for MenuStrip or Context MenuStrip).
Dock Specifies the form edge to line the strip control up against or fill.
RenderMode Strip controls support three render modes:
System: rendered with colors from the system palette.
Professional: rendered according to the current Windows Color Scheme—Blue, Olive Green, or Silver.
ManagerRenderMode: rendered using the Windows Theme sensitive ToolStripRenderer and is the default.
Custom is currently unsupported.
SizingGrip Specifies whether the form sizing grip should be shown or hidden (StatusStrip only).
GripStyle Specifies whether a MenuStrip or ToolStrip displays a grip allowing it to be repositioned.
CanOverflow When the form becomes narrower than a strip control, this option specifies how to visually represent strip items that are hidden by the overlap, either hidden if False or accessible via a dropdown at the end of the strip control if True.

Apart from standard properties you would typically find on controls, including Enabled, Visible, Checked, and BorderStyle, tool strip item controls also have several unique properties which are described in Figure 12.

Figure 12 Key Strip Item Control Property Configurations

Property Description
DisplayStyle Specifies what to display; values include None, Text, Image, and ImageAndText.
TextImageRelation Sets the position of text in relation to an image. Applied when DisplayStyle is ImageAndText.
ImageScaling Specifies how an image is rendered, either ShrinkToFit or None.
Alignment Determines which end of a strip control a strip item control will align to, either Head or Tail (Left or Right sides, respectively, when rendering left-to-right).
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.

ToolStripContainer

Figure 13 Tool Strip

Figure 13** Tool Strip **

By default, strip controls sit where they lay at design time and run time. However, additional support for strip controls can be employed to enable developers and users to drag them from one form edge to another. If this is a feature you need to provide, you can use the new ToolStripContainer control. ToolStripContainer comprises four tool strip panels, shown in Figure 13 as blue, that surround a content panel, shown in gray.

The content panel is for the controls from which you'd normally compose your form. Tool strip panels are designed to house strip controls. The four buttons you can see on the edges of the tool strip panels expand and collapse the size of each tool strip panel by the height or width required for a single tool strip control. When you drag your strip controls onto the tool strip panels at design time, they are stacked horizontally or vertically next to one another. To change their position within the stacks, simply drag them to the new desired location. Z-Order is used to store and apply a strip control's stack position, with higher Z-Ordered strip controls residing closer to the form edge.

At run time, strip controls appear in their default tool strip panels when a form loads. Figure 14 illustrates how users can subsequently drag them from one form edge to another, as long as a ToolStripContainer was used.

Figure 14 Dragging a Strip

Figure 14** Dragging a Strip **

When a strip control is relocated to another tool strip panel, the tool strip container is shifted to make room. The benefit here is that all controls contained within the tool strip container are also shifted, saving you the trouble of doing the repositioning manually.

Strip Control Settings Management

Strip controls can have a lot happen to them at run time, with all the repositioning and strip item reordering going on. Since these are user changes, a good application should ensure that they are persisted across application sessions. Strip controls provide two properties that will make sure this happens automatically: SaveSettings and SettingsKey. SaveSettings is a Boolean that by default is set to False. When set to True by the developer, the strip controls persists values including raft position, location, size, and strip item control arrangement to the user settings subsystem that you saw earlier. SettingsKey is a String value that identifies the set of persisted values in the settings file:

FormName.StripControlName

You can change this as necessary, but once enabled, those values are automatically retrieved from user settings and applied to the strip control to make sure it is positioned correctly each time the application loads. Only strip controls and strip control items provide this feature currently, although you can add settings support in your own custom controls.

MaskedTextBox Control

Another new control, MaskedTextBox, is used for data entry. You use mask characters at design time to specify the type of data that can be entered and its format. For example, the mask character "9" specifies that a user can enter either a space or any number from 0 to 9, while the mask character "0" requires a number be entered. Of course, there is a wide range of mask characters, covering numbers, letters, punctuation, and spacing. Please refer to the evolving Visual Studio documentation for specific details. Developers can build a mask by setting the MaskedTextBox's Mask property with the appropriate mask value. The Input Mask editor, shown in Figure 15, lets you choose an existing common mask or construct your own, and it allows you to test them dynamically.

Figure 15 Input Mask Editor

Figure 15** Input Mask Editor **

Non-mask characters, such as parentheses, hyphens, and spaces, are treated as literals and are shown at run time to help build a stronger visual cue about the type of data that's being entered. On the other hand, all mask characters are replaced by a prompt character at run time (underscore by default), highlighting where the user should key in the data. At run time, the prompt characters are shown only when a MaskedTextBox has the focus.

MaskedTextBox implements a wide variety of properties (see Figure 16). It's a highly configurable control that you should utilize to give users a more informed data entry experience.

Figure 16 Key MaskedTextBox Properties

Property Description
HidePromptOnLeave True by default but, if set to False, ensures that 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 when neither can be reasonably changed.
IncludeLiterals Specifies whether to include literal character values in MaskedTextBox's Text property.
IncludePrompts Specifies whether to include prompt character values in MaskedTextBox's Text property.
ResetOnPrompt If True, when a prompt is entered, a prompt is inserted and values on the right-hand side are shifted right.
ResetOnSpace If True, when a space is entered, a space is inserted and values on the right-hand side are shifted right.

Data Binding

In our previous article, we looked at two new controls in the data binding space, GridView and DataContainer. Just as WinBar underwent substantial changes, so too have both data controls. GridView is now known as DataGridView, and DataContainer has been split into two new components, BindingSource and BindingNavigator. In fact, there have been many changes across the entire data binding subsystem; we'll explore the most notable of these changes.

Figure 17 Data Sources

Figure 17** Data Sources **

A data binding needs a data source. You'll find it much easier to create in Visual Studio 2005. The simplest way is to select Data | Add New Data Source, which opens the Data Source Configuration Wizard. Your choice of data source has increased somewhat to include databases (as you'd expect), Web services, and other objects. If you were to create a data source from a database, not only would a new typed DataSet be added to your project, but you could also view it from the new Data Sources tool window (Tools | Data | Show Data Sources), shown in Figure 17.

The Data Sources tool window allows you to edit your data source with the typed DataSet designer, reconfigure the selected data source, refresh an existing data source, or add a new one. If you haven't already created a data source using these techniques, controls like DataGridView will prompt you to select or create an existing one when they are dropped on the form.

Binding to a Data Source

Just as there are several ways to create a data source, there are also several ways to bind controls to them. First, you can drag tables and fields from the Data Source tool window directly onto your forms. Behind the scenes, this simple act makes several important changes to your form, including:

  • Adding a typed DataSet component to which your controls will bind
  • •Adding a typed data adapter, if the datasource is a database, which assists with the loading and updating of your data
  • •Adding a BindingSource component to expose the data source (discussed in the following text)
  • •Adding a BindingNavigator component to the form for data browsing (discussed in the following text)
  • •Creating or updating the form's Load event handler to automatically load data from the data source
  • •And, of course, adding a control that's automatically bound to the field or table you dragged

How does the designer determine which type of control to create and bind to? In Figure 17, you'll notice that both the Employees table and fields have an icon next to them. This icon represents the type of control that will be created when either a table or field is dragged onto the form. Figure 18 shows how you can configure the control type from the Data Source tool window.

Figure 18 Set Control Type

Figure 18** Set Control Type **

Most options are obvious; "[None]" prohibits a table or field from being dragged onto the form at all. "Customize..." allows you to specify which controls you can create for each possible data type, or which listing style for tables. When a field is dragged onto a form, both the specified control type and a Label control are created. If the source field's name is reasonably well formatted, the designer uses simple heuristics to convert it into a properly spaced and cased text value the new Label control displays. For example, "EmployeeID" becomes "EmployeeID:".

New Data-Bound Components

When a data source is dragged onto a form as a DataGridView, BindingSource and BindingNavigator components are also added to the form. Between a data-bound control and its data source exists a BindingManager whose jobs include:

  • Managing the set of bindings between a bound control and its data source
  • Keeping bound controls up to date when underlying data sources change (and vice versa)
  • Tracking the current record (or currency)

Complex data bound controls, such as a DataGridView, know how to access and use a BindingManager to help perform all of these functions. However, in simple binding scenarios such as binding a TextBox's Text property to a list's data field, there is no such support. Instead, you had to manually write your own code to access and use a BindingManager. For example, the following code moves to the next record of a list data source such as a database table:

void nextButton_Click(object sender, 
  EventArgs e) {
  // Move to the next record
  Binding binding = nameTextBox.DataBindings["Text"];
  BindingManagerBase manager = binding.BindingManagerBase;
  manager.Position = manager.Position + 1;
}

To save you all this effort, the BindingSource was created to wrap binding managers and expose them through a single component-based interface. Much like other complex bound controls, you bind a BindingSource to a data source by setting its DataSource and DataMember properties. This ultimately allows the BindingSource to access the binding manager and, through the BindingSource's interface, allows you to much more easily utilize it. The BindingSource uses reflection to determine which fields are exposed by the underlying data source and exposes them through its own IBindingList implementation. This means that you can bind the Text property (or any property) of a TextBox control (or any control) directly to the BindingSource. This effort reduces the code from the previous sample to just one line, as shown here:

void nextButton_Click(object sender, EventArgs e) {
  // Move to the next record
  this.employeesBindingSource.MoveNext();
}

Figure 19 Binding Navigator

Figure 19** Binding Navigator **

If it's VCR-style navigation you're after, you can use a BindingNavigator component, shown in Figure 19, to avoid having to write any code at all. A BindingNavigator is a specialized strip control that binds to a BindingSource via its BindingSource property, which is used by default BindingNavigator buttons to manage data source navigation. Because BindingNavigator is a strip control, you can reconfigure it by either altering the default tool strip item configuration or extending it with new tool strip items, for example to load and save bound data.

Where Are We?

In this article, we covered a subset of new and improved Windows Forms features found in the December 2004 CTP release of both the .NET Framework 2.0 and Visual Studio 2005. We started by exploring some new Visual Studio 2005 features, including improved resource and application settings management, which also generates strongly typed interfaces. We moved on to look at productivity-focused updates to the System.Windows.Forms.Form class. The design-time experience has also gotten productivity-enhancing improvements that include a wide variety of layout support. The same applies to the tantalizing new strip controls, MaskedTextBox control, and a slew of improvements across the data-binding infrastructure, including the DataGridView, BindingSource, and BindingNavigator.

Windows Forms 2.0 contains significant productivity and feature updates well over and above its .NET Framework 1.x predecessors. Consequently, you should seriously consider it as your Windows Forms development platform for the next several years.

Chris Sells is a Content Strategist for MSDN online, currently focused on "Longhorn," the next version of Windows and smart clients. More information is available at www.sellsbrothers.com.

Michael Weinhardt is currently co-updating Chris Sells's book, Windows Forms Programming in C#, and writes a monthly column for MSDN online called "Wonders of Windows Forms." Visit www.mikedub.net for further information.