Tải bản đầy đủ (.pdf) (140 trang)

Pro C# 2008 and the .NET 3.5 Platform, Fourth Edition phần 9 doc

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (5.27 MB, 140 trang )

Figure 29-23. Grid types containing splitters
■Source Code The GridWithSplitter.xaml file can be found under the Chapter 29 subdirectory.
Positioning Content Within DockPanel Panels
DockPanel is typically used as a master panel that contains any number of additional panels for
grouping of related content.
DockPanels make use of attached property syntax as seen with the
Canvas type, to control where their upper-left corner (the default) will attach itself within the panel.
Here is a very simple
DockPanel definition, which results in the output shown in Figure 29-24:
<DockPanel LastChildFill ="True">
<! Dock items to the panel >
<Label DockPanel.Dock ="Top" Name="lblInstruction"
FontSize="15">Enter Car Information</Label>
<Label DockPanel.Dock ="Left" Name="lblMake">Make</Label>
<Label DockPanel.Dock ="Right" Name="lblColor">Color</Label>
<Label DockPanel.Dock ="Bottom" Name="lblPetName">Pet Name</Label>
<Button Name="btnOK">OK</Button>
</DockPanel>
Figure 29-24. A simple DockPanel
■Note If you add multiple elements to the same side of a DockPanel, they will be stacked along the specified
edge in the order that they are declared.
The benefit of using DockPanel types is that as the user resizes the window, each element
remains “connected” to the specified side of the panel (via
DockPanel.Dock). Also notice that the
opening
<DockPanel> element sets the LastChildFill attribute to true. Given that the Button type
has not specified any
DockPanel.Dock value, it will therefore be stretched within the remaining
space.
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1092
8849CH29.qxd 10/16/07 12:17 PM Page 1092


www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
■Source Code The SimpleDockPanel.xaml file can be found under the Chapter 29 subdirectory.
Enabling Scrolling for Panel Types
It is worth pointing out the WPF supplies a <ScrollViewer> type, which provides automatic scrolling
behaviors for nested panel types:
<ScrollViewer>
<StackPanel>
<Button Content ="First" Background = "Green" Height ="40"/>
<Button Content ="Second" Background = "Red" Height ="40"/>
<Button Content ="Third" Background = "Pink" Height ="40"/>
<Button Content ="Fourth" Background = "Yellow" Height ="40"/>
<Button Content ="Fifth" Background = "Blue" Height ="40"/>
</StackPanel>
</ScrollViewer>
The result of the previous XAML definition is shown in Figure 29-25.
Figure 29-25. Working with the ScrollViewer type
■Source Code The ScrollViewer.xaml file can be found under the Chapter 29 subdirectory.
As you would expect, each panel provides numerous members that allow you to fine-tune con-
tent placement. On a related note, WPF controls all support two properties of interest (
Padding and
Margin) that allow the control itself to inform the panel how it wishes to be treated. Specifically, the
Padding property controls how much extra space should surround the interior control, while Margin
controls the extra space around the exterior of a control.
This wraps up our look at the major panel types of WPF, and the various ways they position
their content. Next, we will see an example using nested panels to create a layout system for a main
window. To do so, we will enhance the functionality of the TextControls project (e.g., the spell-
checker app) to support a main menu, a status bar, and a toolbar.
Building a Window’s Frame Using Nested Panels
This updated version of the application (which we will assume is a new Visual Studio 2008 WPF

Application project named MySpellChecker) will be extended and finalized over the pages to come,
so for the time being, you will construct the core layout and base functionality.
Our goal is to construct a layout where the main window has a topmost menu system, a tool-
bar, and a status bar mounted on the bottom of the window. The status bar will contain a pane to
hold text prompts that are displayed when the user selects a menu item (or toolbar button), while
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1093
8849CH29.qxd 10/16/07 12:17 PM Page 1093
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
the menu system and toolbar will offer UI triggers to close the application and display spelling sug-
gestions in an
Expander widget. Figure 29-26 shows the initial layout we are shooting for, displaying
spelling suggestions for “XAML.”
Figure 29-26. Using nested panels to establish a window’s UI
Notice that our two toolbar buttons are not supporting an expected image, but a simple text
value. While this would not be sufficient for a production-level application, assigning images to
toolbar buttons typically involves using embedded resources, a topic that you will examine in
Chapter 30 (so text data will do for now). Also note that as the mouse button is placed over the
Check button, the mouse cursor changes and the single pane of the status bar displays a useful UI
message.
To begin building this UI, update the initial XAML definition for your
Window type to make use
of a
<DockPanel> child element, rather than the default <Grid>:
<Window x:Class="MySpellChecker.MainWindow"
xmlns=" />xmlns:x=" />Title="MySpellChecker" Height="331" Width="508"
WindowStartupLocation ="CenterScreen" >
<! This panel establishes the content for the window >
<DockPanel>
</DockPanel>

</Window>
Building the Menu System
Menu systems in WPF are represented by the Menu type, which maintains a collection of MenuItem
objects. When building a menu system in XAML, each MenuItem may handle various events, most
notably
Click, which occurs when the end user selects a subitem. In our example, we will build two
topmost menu items (File and Tools), which expose Exit and Spelling Hints subitems (respectively).
In addition to handling the
Click event for each subitem, we will also handle the MouseEnter and
MouseExit events, which will be used to set the status bar text in a later step. Add the following
markup within your
<DockPanel> scope:
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1094
8849CH29.qxd 10/16/07 12:17 PM Page 1094
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
<! Doc menu system on the top >
<Menu DockPanel.Dock ="Top"
HorizontalAlignment="Left" Background="White" BorderBrush ="Black">
<MenuItem Header="_File" Click ="FileExit_Click" >
<Separator/>
<MenuItem Header ="_Exit" MouseEnter ="MouseEnterExitArea"
MouseLeave ="MouseLeaveArea" Click ="FileExit_Click"/>
</MenuItem>
<MenuItem Header="_Tools">
<MenuItem Header ="_Spelling Hints" MouseEnter ="MouseEnterToolsHintsArea"
MouseLeave ="MouseLeaveArea" Click ="ToolsSpellingHints_Click"/>
</MenuItem>
</Menu>
Notice that we have docked the menu system to the top of the DockPanel. As well, the

<Separator> element has been used to insert a thin horizontal line in the menu system, directly
before the Exit option. Also notice that the
Header values for each MenuItem contain an embedded
underbar token (for example,
_Exit). This is used to establish which letter will be underlined when
the end user presses the Alt key (for keyboard shortcuts).
The complete the menu system definition, we now need to implement the various event han-
dlers. First, we have the File
➤ Exit handler, FileExit_Click(), which will simply terminate the
application via
Application.Current.Shutdown(). The MouseEnter and MouseExit event handlers for
each subitem will eventually update our status bar; however, for now, we will simply provide shells.
Finally, the
ToolsSpellingHints_Click() handler for the Tools ➤ Spelling Hints menu item will also
be a shell for the time being. Here are the current updates to your code-behind file:
public partial class MainWindow : System.Windows.Window
{
public MainWindow()
{
InitializeComponent();
}
protected void FileExit_Click(object sender, RoutedEventArgs args)
{
// Terminate the application.
Application.Current.Shutdown();
}
protected void ToolsSpellingHints_Click(object sender, RoutedEventArgs args)
{
}
protected void MouseEnterExitArea(object sender, RoutedEventArgs args)

{
}
protected void MouseEnterToolsHintsArea(object sender, RoutedEventArgs args)
{
}
protected void MouseLeaveArea(object sender, RoutedEventArgs args)
{
}
}
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1095
8849CH29.qxd 10/16/07 12:17 PM Page 1095
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
Building the ToolBar Type
Toolbars (represented by the ToolBar type in WPF) typically provide an alternative manner to acti-
vate a menu option. Add the following markup directly after the closing scope of your
<Menu>
definition:
<! Put Toolbar under the Menu >
<ToolBar DockPanel.Dock ="Top" >
<Button Content ="Exit" MouseEnter ="MouseEnterExitArea"
MouseLeave ="MouseLeaveArea" Click ="FileExit_Click"/>
<Separator/>
<Button Content ="Check" MouseEnter ="MouseEnterToolsHintsArea"
MouseLeave ="MouseLeaveArea" Click ="ToolsSpellingHints_Click"
Cursor="Help" />
</ToolBar>
Our <ToolBar> type consists of two Button types, which just so happen to handle the same
events and are handled by the same methods in our code file. Using this technique, we are able to
double-up our handlers to serve both menu items and toolbar buttons. Although this toolbar is

making use of the typical push buttons, do know that the
ToolBar type “is-a” ContentControl, and
therefore you are free to embed any types into its surface (drop-down lists, images, graphics, etc.).
The only other point of interest is that the Check button supports a custom mouse cursor via the
Cursor property.
■Note The ToolBar type may optionally be wrapped within a <ToolBarTray> element, which controls layout,
docking, and drag-and-drop operations for a set of
ToolBar objects. Consult the .NET Framework 3.5 SDK docu-
mentation for details.
Building the StatusBar Type
The StatusBar type will be docked to the lower portion of the <DockPanel> and contain a single
<TextBlock> type, which up until this point in the chapter we have not made use of. Like a TextBox,
a
TextBlock can be used to hold text. In addition, TextBlock types honor the use of numerous tex-
tual annotations such as bold text, underlined text, line breaks, and so forth. While our
StatusBar
does not technically need this support, another benefit of a TextBlock type is that it is optimized for
small blurbs of text, such as UI prompts in a status bar pane. Add the following markup directly
after the previous
ToolBar definition:
<! Put a StatusBar at the bottom >
<StatusBar DockPanel.Dock ="Bottom" Background="Beige" >
<StatusBarItem>
<TextBlock Name="statBarText">Ready</TextBlock>
</StatusBarItem>
</StatusBar>
At this point, your Visual Studio designer should look something like Figure 29-27.
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1096
8849CH29.qxd 10/16/07 12:17 PM Page 1096
www.free-ebooks-download.org

Simpo PDF Merge and Split Unregistered Version -
Figure 29-27. The current user interface of our spell-checker application
Finalizing the UI Design
The final aspect of our UI design is to define a splittable Grid type that defines two columns. On
the left will be the
Expander type that will display a list of spelling suggestions, wrapped within a
<StackPanel>. On the right will be a TextBox type that supports multiple lines and has enabled spell
checking. The entire
<Grid> will be mounted to the left of the parent <DockPanel>. Add the following
XAML markup to complete the definition of our Window’s UI:
<Grid DockPanel.Dock ="Left" Background ="AliceBlue">
<! Define the rows and columns >
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column ="0" Width ="5" Background ="Gray" />
<StackPanel Grid.Column="0" VerticalAlignment ="Stretch" >
<Label Name="lblSpellingInstructions" FontSize="14" Margin="10,10,0,0">
Spelling Hints
</Label>
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1097
8849CH29.qxd 10/16/07 12:17 PM Page 1097
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
<Expander Name="expanderSpelling" Header ="Try these!" Margin="10,10,10,10">
<! This will be filled programmatically >
<Label Name ="lblSpellingHints" FontSize ="12"/>
</Expander>
</StackPanel>

<! This will be the area to type within >
<TextBox Grid.Column ="1"
SpellCheck.IsEnabled ="True"
AcceptsReturn ="True"
Name ="txtData" FontSize ="14"
BorderBrush ="Blue">
</TextBox>
</Grid>
Finalizing the Implementation
At this point, your UI is complete. The only remaining tasks are to provide an implementation for
the remaining event handlers. Here is the relevant code in question, which requires little comment
by this point in the chapter:
public partial class MainWindow : System.Windows.Window
{

protected void ToolsSpellingHints_Click(object sender, RoutedEventArgs args)
{
string spellingHints = string.Empty;
// Try to get a spelling error at the current caret location.
SpellingError error = txtData.GetSpellingError(txtData.CaretIndex);
if (error != null)
{
// Build a string of spelling suggestions.
foreach (string s in error.Suggestions)
{
spellingHints += string.Format("{0}\n", s);
}
// Show suggestions on Label within Expander.
lblSpellingHints.Content = spellingHints;
// Expand the expander.

expanderSpelling.IsExpanded = true;
}
}
protected void MouseEnterExitArea(object sender, RoutedEventArgs args)
{
statBarText.Text = "Exit the Application";
}
protected void MouseEnterToolsHintsArea(object sender, RoutedEventArgs args)
{
statBarText.Text = "Show Spelling Suggestions";
}
protected void MouseLeaveArea(object sender, RoutedEventArgs args)
{
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1098
8849CH29.qxd 10/16/07 12:17 PM Page 1098
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
statBarText.Text = "Ready";
}
}
So there you have it! With just a few lines of procedural code (and a healthy dose of XAML), we
have the beginnings of a functioning word processor. To add just a bit more pizzazz requires an
understanding of
control commands.
Understanding WPF Control Commands
The next major discussion of this chapter is to examine the topic of control commands. Windows
Presentation Foundation provides support for what might be considered “control-agnostic events”
via control commands. As you know, a typical .NET event is defined within a specific base class and
can only be used by that class or a derivative thereof. Furthermore, normal .NET events are tightly
coupled to the class in which they are defined.

In contrast, WPF control commands are event-like entities that are independent from a specific
control and in many cases can be successfully applied to numerous (and seemingly unrelated) con-
trol types. By way of a few examples, WPF supports Copy, Paste, and Cut commands, which can be
applied to a wide variety of UI elements (menu items, toolbar buttons, custom buttons) as well as
keyboard shortcuts (Ctrl+C, Ctrl+V, etc.).
While other UI toolkits (such as Windows Forms) provided standard events for such purposes,
the end result was typically redundant and hard to maintain code. Under the WPF model, com-
mands can be used as an alternative. The end result typically yields a smaller and more flexible
code base.
The Intrinsic Control Command Objects
WPF ships with numerous built-in control commands, all of which can be configured with associ-
ated keyboard shortcuts (or other input gestures). Programmatically speaking, a WPF control
command is any object that supports a property (often called
Command) that returns an object imple-
menting the
ICommand interface, shown here:
public interface ICommand
{
// Occurs when changes occur that affect whether
// or not the command should execute.
event EventHandler CanExecuteChanged;
// Defines the method that determines whether the command
// can execute in its current state.
bool CanExecute(object parameter);
// Defines the method to be called when the command is invoked.
void Execute(object parameter);
}
While you could provide your own implementation of this interface to account for a control
command, the chances that you will need to are slim, given functionality provided by the five WPF
command objects out of the box. These static classes define numerous properties that expose

objects that implement
ICommand, most commonly the RoutedUICommand type, which adds support
for the WPF routed event model.
Table 29-4 documents some core properties exposed by each of the intrinsic command objects
(be sure to consult the .NET Framework 3.5 SDK documentation for complete details).
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1099
8849CH29.qxd 10/16/07 12:17 PM Page 1099
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
Table 29-4. The Intrinsic WPF Control Command Objects
WPF Control Command Object Example Control Command Properties Meaning in Life
ApplicationCommands Close, Copy, Cut, Delete, Find, Open, Defines properties that
Paste, Save, SaveAll, Redo, Undo represent application-
level commands
ComponentsCommands MoveDown, MoveFocusBack, MoveLeft, Defines properties that
MoveRight, ScrollToEnd, map to common
ScrollToHome commands performed by
UI elements
MediaCommands BoostBase, ChannelUp, ChannelDown, Defines properties that
FastForward, NextTrack, Play, allow various media-
Rewind, Select, Stop centric controls to issue
common commands
NavigationCommands BrowseBack, BrowseForward, Defines numerous
Favorites, LastPage, NextPage, properties that are used
Zoom for the applications that
utilize the WPF
navigation model
EditingCommands AlignCenter, CorrectSpellingError, Defines numerous
DecreaseFontSize, EnterLineBreak, properties typically used
EnterParagraphBreak, MoveDownByLine, when programming with

MoveRightByWord objects exposed by the
WPF document API
Connecting Commands to the Command Property
If you wish to connect any of these command properties to a UI element that supports the Command
property (such as a Button or MenuItem), you have very little work to do. To see how to do so, update
the current menu system to support a new topmost menu item named Edit and three subitems to
account for copying, pasting, and cutting of textual data:
<Menu DockPanel.Dock ="Top"
HorizontalAlignment="Left" Background="White" BorderBrush ="Black">
<MenuItem Header="_File" Click ="FileExit_Click" >
<Separator/>
<MenuItem Header ="_Exit" MouseEnter ="MouseEnterExitArea"
MouseLeave ="MouseLeaveArea" Click ="FileExit_Click"/>
</MenuItem>
<! New menu item with commands! >
<MenuItem Header="_Edit">
<MenuItem Command ="ApplicationCommands.Copy"/>
<MenuItem Command ="ApplicationCommands.Cut"/>
<MenuItem Command ="ApplicationCommands.Paste"/>
</MenuItem>
<MenuItem Header="_Tools">
<MenuItem Header ="_Spelling Hints" MouseEnter ="MouseEnterToolsHintsArea"
MouseLeave ="MouseLeaveArea" Click ="ToolsSpellingHints_Click"/>
</MenuItem>
</Menu>
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1100
8849CH29.qxd 10/16/07 12:17 PM Page 1100
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
Notice that each subitem has a value assigned to the Command property. By doing so, the menu

items automatically receive the correct name and shortcut key (for example, Ctrl+C for a cut
operation) in the menu item UI and the application is now “copy, cut, and paste” aware with no
procedural code. Thus, if you were to run the application and select some of your text, you will
be able to use your new menu items out of the box, as shown in Figure 29-28.
Figure 29-28. Command objects provide a good deal of canned functionality for free.
Connection Commands to Arbitrary UI Elements
If you wish to connect a command to a UI element that does not support the Command property,
doing so requires you to drop down to procedural code. Doing so is certainly not complex, but it
does involve a bit more logic than you see in XAML. For example, what if you wished to have the
entire window respond to the F1 key, so that when the end user presses this key, he or she would
activate an associated help system?
Assume your code file for the main window defines a new method named
SetF1CommandBinding(), which is called within the constructor after the call to InitializeComponent().
This new method will programmatically create a new
CommandBinding object, which is configured to
operate with the
ApplicationCommands.Help option, which is automatically F1-aware:
private void SetF1CommandBinding()
{
CommandBinding helpBinding = new CommandBinding(ApplicationCommands.Help);
helpBinding.CanExecute += CanHelpExecute;
helpBinding.Executed += HelpExecuted;
CommandBindings.Add(helpBinding);
}
Most CommandBinding objects will want to handle the CanExecute event (which allows you to
specify whether the command occurs or not based on the operation of your program) and the
Executed event (which is where you can author the content that should occur once the command
occurs). Add the following event handlers to your
Window-derived type (take note of the format of
each method as required by the associated delegates):

private void CanHelpExecute(object sender, CanExecuteRoutedEventArgs e)
{
// Here, you can set CanExecute to false if you wish to prevent the
// command from executing if you desire.
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1101
8849CH29.qxd 10/16/07 12:17 PM Page 1101
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
e.CanExecute = true;
}
private void HelpExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Dude, it is not that difficult. Just type something!",
"Help!");
}
Here, we have implemented CanHelpExecute() to always allow F1 help to occur by simply
returning
true. However, if you have certain situations where the help system should not display,
you can account for this and return
false when necessary. Our “help system” displayed within
HelpExecute() is little more than a message box. At this point, you can run your application. When
you press the F1 key on your keyboard, you will see your (less than helpful, if not a bit insulting)
user guidance system (see Figure 29-29).
Figure 29-29. Our custom help system
■Source Code The MySpellChecker project can be found under the Chapter 29 subdirectory.
Understanding the WPF Data-Binding Model
Controls are often the target of various data-binding operations. Simply put, data binding is the act
of connecting control properties to data values that may change over the course of your applica-
tion’s lifetime. By doing so, a user interface element can display the state of a variable in your code;
for example:

• Checking a CheckBox control based on a Boolean property of a given object
• Displaying data in
TextBox types from a relational database table
•A
Label connected to an integer representing the number of files in a folder
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1102
8849CH29.qxd 10/16/07 12:17 PM Page 1102
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
When using the intrinsic WPF data-binding engine, you must be aware of the distinction
between the
source and the destination of the binding operation. As you might expect, the source of
a data-binding operation is the data itself (a Boolean property, relational data, etc.), while the desti-
nation (or target) is the UI control property that will use the data content (a
CheckBox, TextBox, and
so on).
■Note The target property of a data-binding operation must be a dependency property of the UI control.
Truth be told, using the WPF data-binding infrastructure is always optional. If a developer were
to roll his or her own data-binding logic, the connection between a source and destination typically
would involve handling various events and authoring procedural code to connect the source and
destination. For example, if you had a
ScrollBar on a window that needed to display its value on a
Label type, you might handle the ScrollBar’s ValueChange event and update the Label’s content
accordingly.
However, using WPF data binding, you can connect the source and destination directly in
XAML (or using C# code in your code file) without the need to handle various events or hard-code
the connections between the source/destination. As well, based on how you set up your data-binding
logic, you can ensure that the source and destination stay in sync if either of their values change.
A First Look at Data Binding
To begin examining WPF’s data-binding capabilities, assume you have a new WPF Application proj-

ect (named SimpleDataBinding) that defines the following markup for a
Window type:
<Window x:Class="SimpleDataBinding.MainWindow"
xmlns=" />xmlns:x=" />Title="Simple Data Binding" Height="152" Width="300"
WindowStartupLocation="CenterScreen">
<StackPanel Width="250">
<Label Content="Move the scroll bar to see the current value"/>
<! The scrollbar's value is the source of this data bind >
<ScrollBar Orientation="Horizontal" Height="30" Name="mySB"
Maximum = "100" LargeChange="1" SmallChange="1"/>
<! The label's content value is the target of the data bind >
<Label Height="30" BorderBrush="Blue" BorderThickness="2"
Content = "{Binding ElementName=mySB, Path=Value}"
/>
</StackPanel>
</Window>
Notice that the <ScrollBar> type (which we have named mySB) has been configured with a
range between 0 and 100. As you reposition the thumb of the scrollbar (or click the left or right
arrow), the
Label will be automatically updated with the current value. The “glue” that makes this
happen is the
{Binding} markup extension that has been assigned to the Label’s Content property.
Here, the
ElementName value represents the source of the data-binding operation (the ScrollBar
object), while the Path value represents (in this case) the property of the element to obtain.
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1103
8849CH29.qxd 10/16/07 12:17 PM Page 1103
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
■Note ElementName and Path may seem oddly named, as you might expect to find more intuitive names such

as “Source” and “Destination.” However, as you will see later in this chapter, XML documents can be the source of
a data-binding operation (typically using XPath). In this case, the names ElementName and Path fit the bill.
As an alternative format, it is possible to break out the values specified by the {Binding}
markup extension by explicitly setting the DataContext property to the source of the binding opera-
tion as follows:
<! Breaking object/value apart via DataContext >
<Label Height="30" BorderBrush="Blue" BorderThickness="2"
DataContext = "{Binding ElementName=mySB}"
Content = "{Binding Path=Value}"
/>
In either case, if you were to run this application, you would be pleased to find this Label
updating without the need to write any procedural C# code (see Figure 29-30).
Figure 29-30. Binding the ScrollBar value to a Label
The DataContext Property
In the current example, you have seen two approaches to establish the source and destination of a
data-binding operation, both of which resulted in the same output. Given this point, you might
wonder when you would want to explicitly set the
DataContext property. This property can be very
helpful in that it is a dependency property, and therefore its value can be inherited by subelements.
In this way, you can easily set the same data source to a family of controls, rather than having to
repeat a bunch of redundant
"{Binding ElementName=X, Path=Y}" XAML values to multiple con-
trols. Consider the following updated XAML definition for our current
<StackPanel>:
<! Note the StackPanel sets the DataContext property >
<StackPanel Width="250" DataContext = "{Binding ElementName=mySB}">
<Label Content="Move the scroll bar to see the current value"/>
<ScrollBar Orientation="Horizontal" Height="30" Name="mySB"
Maximum = "100" LargeChange="1" SmallChange="1"/>
<! Now both UI elements use the scrollbar's value in unique ways. >

<Label Height="30" BorderBrush="Blue" BorderThickness="2"
Content = "{Binding Path=Value}"/>
<Button Content="Click" Height="200"
FontSize = "{Binding Path=Value}"/>
</StackPanel>
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1104
8849CH29.qxd 10/16/07 12:17 PM Page 1104
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
Here, the DataContext property has been set on the <StackPanel> directly. Therefore, as we
move the thumb, not only will we see the current value on the
Label, but we will also find the font
size of the
Button grow and shrink accordingly based on the same value. Figure 29-31 shows one
possible output.
Figure 29-31. Binding the ScrollBar value to a Label and a Button
The Mode Property
When establishing a data-binding operation, you are able to choose among various modes of oper-
ation by setting a value to the
Mode property at the time you establish the Path value. By default, the
Mode property is set to the value OneWay, which specifies that changes in the target do not affect the
source. In our example, changing the
Content property of the Label does not set the position of the
ScrollBar’s thumb.
If you wish to keep changes between the source and the target in sync, you can set the
Mode
property to TwoWay. Thus, changing the value of the Label’s content changes the value of the scroll-
bar’s thumb position. Of course, the end user would be unable to change the content of the
Label,
as the content is presented in a read-only manner (we could of course change the value program-

matically).
To illustrate the use of the
TwoWay mode, assume we have replaced the Label displaying the cur-
rent scrollbar value with the following
TextBox (note the value of the Text property). In this case,
when you type a new value into the text area, the thumb position (and font of the
Button type) auto-
matically update when you tab off the
TextBox object:
<TextBox Height="30" BorderBrush="Blue"
BorderThickness="2" Text = "{Binding Path=Value}"/>
■Note You may also set the Mode property to OneTime. This option sets the target when initialized but does not
track further changes.
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1105
8849CH29.qxd 10/16/07 12:17 PM Page 1105
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
Data Conversion Using IValueConverter
The ScrollBar type uses a double to represent the value of the thumb, rather than an expected
whole number (e.g., an integer). Therefore, as you drag the thumb, you will find various floating-
point numbers displayed within the
TextBox (such as 61.0576923076923), which would be rather
unintuitive to the end user, who is most likely expecting to see whole numbers (such as 61, 62, 63,
and so on).
When you wish to convert the value of a data-binding operation into an alternative format, one
way to do so is to create a custom class type that implements the
IValueConverter interface of the
System.Windows.Data namespace. This interface defines two members that allow you to perform the
conversion to and from the target and destination. Once you define this class, you can use it to fur-
ther qualify the processing of your data-binding operation.

■Note While any data-binding operation can be achieved entirely using procedural code, the following examples
will make use of XAML to convert between data types. Doing so involves the use of custom resources, which will
be fully examined in Chapter 30. Therefore, don’t fret if some of the markup appears unfamiliar.
Assuming that you wish to display whole numbers within the TextBox control, you could build
the following class type (be sure you import the
System.Windows.Data namespace in the defining
file):
class MyDoubleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
// Convert the double to an int.
double v = (double)value;
return (int)v;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
// Return the incoming value directly.
// This will be used for 2-way bindings.
// In our example, when the user tabs
// off the TextBlock.
return value;
}
}
The Convert() method will be called when the value is transferred from the source (the
ScrollBar) to the destination (the Text property of the TextBox). While we receive a number of
incoming arguments, for this conversion we only need to manipulate the incoming
object, which is

the value of the current
double. Using this type, we simply cast the type into an integer and return
the new number.
The
ConvertBack() method will be called when the value is passed from the destination to the
source (if you have enabled a two-way binding mode). Here, we simply return the value straight-
away. By doing so, we are able to type a floating-point value into the
TextBox (such as 99.9) and have
it automatically convert to a whole number value (99) when the user tabs off the control. This “free”
conversion happens due to the fact that the
Convert() method is called once again after a call to
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1106
8849CH29.qxd 10/16/07 12:17 PM Page 1106
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
ConvertBack(). If you were to simply return null from ConvertBack(), your binding would appear to
be out of sync, as the text box would still be displaying a floating-point number!
With this class in place, consider the following XAML updates, which will leverage our custom
converter class to display data in the
TextBox:
<Window x:Class="SimpleDataBinding.MainWindow"
xmlns=" />xmlns:x=" /><! Need to define a CLR namespace to gain access to our type >
xmlns:myConverters ="clr-namespace:SimpleDataBinding"
Title="Simple Data Binding" Height="334" Width="288"
WindowStartupLocation="CenterScreen">
<! Resource dictionaries allow us to define objects that can
be obtained by their key. More details in Chapter 30. >
<Window.Resources>
<myConverters:MyDoubleConverter x:Key="DoubleConverter"/>
</Window.Resources>

<! The panel is setting the data context to the scrollbar object >
<StackPanel Width="250" DataContext = "{Binding ElementName=mySB}">
<Label Content="Move the scroll bar to see the current value"/>
<ScrollBar Orientation="Horizontal" Height="30" Name="mySB"
Maximum = "100" LargeChange="1" SmallChange="1"/>
<! Notice that the {Binding} extension now sets the Converter property. >
<TextBox Height="30" BorderBrush="Blue" BorderThickness="2" Name="txtThumbValue"
Text = "{Binding Path=Value, Converter={StaticResource DoubleConverter}}"/>
<Button Content="Click" Height="200"
FontSize = "{Binding Path=Value}"/>
</StackPanel>
</Window>
Once we define a custom XML namespace that maps to our project’s root namespace (see
Chapter 28), we add to the
Window’s resource dictionary an instance of our MyDoubleConverter type,
which we can obtain later in the XAML file by the key name
DoubleConverter. The Text property of
the
TextBox has been modified to make use of our MyDoubleConverter type, assigning the Converter
property to yet another markup extension named StaticResource. Again, full details of the WPF
resource system can be found in Chapter 30. In any case, if you were to run your application, you
would find that only whole numbers will be displayed in the
TextBox.
Converting Between Diverse Data Types
An implementation of the IValueConverter interface can be used to convert between any data
types, even if they do not seem related on the surface. In reality, you are able to use the current
value of the
ScrollBar’s thumb to return any object type to connect to a dependency property. Con-
sider the following
ColorConverter type, which uses the value of the thumb to return a new green

SolidColorBrush (with a green value between 155 and 255):
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1107
8849CH29.qxd 10/16/07 12:17 PM Page 1107
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
class MyColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
// Use value of thumb to build a varied green brush.
double d = (double)value;
byte v = (byte)d;
Color color = new Color();
color.A = 255;
color.G = (byte) (155 + v);
return new SolidColorBrush(color);
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return value;
}
}
If we were to add a new member to our resource dictionary as follows:
<Window.Resources>
<myConverters:MyDoubleConverter x:Key="DoubleConverter"/>
<myConverters:MyColorConverter x:Key="ColorConverter"/>
</Window.Resources>
we could then use the key name to set the Background property of our Button type as follows:

<Button Content="Click" Height="200"
FontSize = "{Binding Path=Value}"
Background= "{Binding Path=Value, Converter={StaticResource ColorConverter}}"/>
Sure enough, if you run your application once again, you’ll find the color of the Button change
based on the scrollbar’s position. To wrap up our look at WPF data binding, let’s check out how to
map custom objects and XML document data to our UI layer.
■Source Code The SimpleDataBinding project can be found under the Chapter 29 subdirectory.
Binding to Custom Objects
The next flavor of data binding we will examine is how to connect the properties of custom objects
to your UI layer. Begin by creating a new WPF Application project named CarViewerApp and, using
the steps outlined in Chapter 28, change the name of your initial
Window1 type to MainWindow. Next,
handle the
Loaded event of MainWindow, and update the <Grid> definition to contain two rows and
two columns:
<Window x:Class="CarViewerApp.MainWindow"
xmlns=" />xmlns:x=" />Title="Car Viewer Application" Height="294" Width="502"
ResizeMode="NoResize" WindowStartupLocation="CenterScreen"
Loaded="Window_Loaded"
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1108
8849CH29.qxd 10/16/07 12:17 PM Page 1108
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>

<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
</Grid>
</Window>
The first row of the <Grid> will consist of a menu system containing a File menu with two sub-
menus (Add New Car and Exit). Notice that we are handling the
Click event of each submenu, and
that we are assigning an “input gesture” to the Exit menu to allow the item to be activated when the
user presses the Alt+F4 keystroke. Finally, notice the value of
Grid.ColumnSpan has been set to 2,
allowing the menu system to be positioned within each cell of the first row.
<! Menu Bar >
<DockPanel
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="0">
<Menu DockPanel.Dock ="Top" HorizontalAlignment="Left" Background="White">
<MenuItem Header="File">
<MenuItem Header="New Car" Click="AddNewCarWizard"/>
<Separator />
<MenuItem Header="Exit" InputGestureText="Alt-F4"
Click="ExitApplication"/>
</MenuItem>
</Menu>
</DockPanel>
The remaining left portion of the <Grid> consists of a <DockPanel> containing a ListBox, while
the right portion of the
<Grid> contains a single TextBlock. The ListBox type will eventually become
the destination for a data-binding operation involving a collection of custom objects, so set the

ItemsSource property to the {Binding} markup extension (the source of the binding will be specified
in code in just a bit). As the user selects one of the items in the
ListBox, we will capture the
SelectionChanged event in order to update the content within the TextBlock. Here is the definition
of these remaining types:
<! Left pane of grid >
<ListBox Grid.Column="0"
Grid.Row="2" Name="allCars" SelectionChanged="ListItemSelected"
Background="LightBlue" ItemsSource="{Binding}">
</ListBox>
<! Right pane of grid >
<TextBlock Name="txtCarStats" Background="LightYellow"
Grid.Column="1" Grid.Row="2"/>
At this point, the UI of your window should look like what you see in Figure 29-32.
Before we implement the data-binding logic, finalize the File
➤ Exit menu handler as follows:
private void ExitApplication(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1109
8849CH29.qxd 10/16/07 12:17 PM Page 1109
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
Figure 29-32. The UI of our main window
Working with the ObservableCollection<T> Type
.NET 3.0 introduced a new collection type within the System.Collections.ObjectModel namespace
named
ObservableCollection<T>. The benefit of working with this type is that when its contents are
updated, it will send notifications to interested listeners, such as the destination of a data-binding

operation. Insert a new C# file into your application that defines a class named
CarList that extends
ObservableCollection<T>, where T is of type Car. This iteration of the Car type makes use of C# auto-
matic properties to establish some basic state data (which can be set using a custom constructor),
and provides a fitting implementation of
ToString():
using System;
using System.Collections.ObjectModel;
namespace CarViewerApp
{
public class CarList : ObservableCollection<Car>
{
public CarList()
{
// Add a few entries to the list.
Add(new Car(40, "BMW", "Black", "Sidd"));
Add(new Car(55, "VW", "Black", "Mary"));
Add(new Car(100, "Ford", "Tan", "Mel"));
Add(new Car(0, "Yugo", "Green", "Clunker"));
}
}
public class Car
{
public int Speed { get; set; }
public string Make { get; set; }
public string Color { get; set; }
public string PetName { get; set; }
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1110
8849CH29.qxd 10/16/07 12:17 PM Page 1110
www.free-ebooks-download.org

Simpo PDF Merge and Split Unregistered Version -
public Car(int speed, string make, string color, string name)
{
Speed = speed; Make = make; Color = color; PetName = name;
}
public Car(){}
public override string ToString()
{
return string.Format("{0} the {1} {2} is going {3} MPH",
PetName, Color, Make, Speed);
}
}
}
Now, open the code file for your MainWindow class and define a member variable of type CarList
named myCars. Within the Loaded event handler of your Window type, set the DataContext property
of the
allCars ListBox to the myCars object (recall we did not set this value via XAML with the
{Binding} extension, therefore for a change of pace, we will do so using procedural code):
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Set the data context.
allCars.DataContext = myCars;
}
At this point, you should be able to run your application and see the ListBox containing the
ToString() values for each Car in the custom ObservableCollection<T>, as shown in Figure 29-33.
Figure 29-33. The initial data-binding operation
Creating a Custom Data Template
Currently, ListBox is displaying each item in the CarList object; however, because we have not
specified a binding path, each list entry is simply the result of calling
ToString() on the subobjects.

As we have already examined how to establish simple binding paths, this time we will construct a
custom
data template. Simply put, a data template can be used to inform the destination of a data-
binding operation how to display the data connected to it. Our template will fill each item in the
ListBox with a <StackPanel> that consists of an Ellipse object and a TextBlock that has been bound
to the
PetName property of each item in the CarList type. Here is the modified markup of the
ListBox type.
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1111
8849CH29.qxd 10/16/07 12:17 PM Page 1111
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
<ListBox Grid.Column="0"
Grid.Row="2" Name="allCars" SelectionChanged="ListItemSelected"
Background="LightBlue" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Height="10" Width="10" Fill="Blue"/>
<TextBlock FontStyle="Italic" FontSize="14" Text="{Binding Path=PetName}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here we connect our <DataTemplate> to the ListBox using the <ListBox.ItemTemplate> ele-
ment. Before we see the result of this data template, implement the
SelectionChanged handler of
your
ListBox to display the ToString() of the current selection within the rightmost TextBlock:
private void ListItemSelected(object sender, SelectionChangedEventArgs e)

{
// Get correct car from the ObservableCollection based
// on the selected item in the list box. Then call toString().
txtCarStats.Text = myCars[allCars.SelectedIndex].ToString();
}
With this update, you should now see a more stylized display of our data, as shown Figure 29-34.
Figure 29-34. Data binding with a custom data template
Binding UI Elements to XML Documents
The next task is to build a custom dialog box that will use data binding to display the content of an
external XML file within a stylized
ListView object. First, insert the Inventory.xml file you created in
Chapter 24 during the NavigationWithLinqToXml project using the Project
➤ Add Existing Item
menu option. Select this item within the Solution Explorer, and using the Properties window, set the
Copy to Output Directory option to Copy Always. This will ensure that when you compile your
application, the
Inventory.xml file will be copied to your \bin\Debug folder.
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1112
8849CH29.qxd 10/16/07 12:17 PM Page 1112
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
Building a Custom Dialog
Insert a new WPF Window type into your project (named AddNewCarDialog) using the Project ➤ Add
Window menu option of Visual Studio 2008. This new
Window will display the content of the
Inventory.xml file within a customized ListView type, via data binding. The first step is to author
the XAML to define the look and feel of this new window. Here is the full markup, with analysis to
follow:
<Window x:Class="CarViewerApp.AddNewCarDialog"
xmlns=" />xmlns:x=" />Title="AddNewCarDialog" Height="234" Width="529"

ResizeMode="NoResize" WindowStartupLocation="CenterScreen" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="144" />
<RowDefinition Height="51" />
</Grid.RowDefinitions>
<! Use the XmlDataProvider >
<Grid.Resources>
<XmlDataProvider x:Key="CarsXmlDoc"
Source="Inventory.xml"/>
</Grid.Resources>
<! Now, build a grid of data, mapping attributes/elements to columns
using XPath expressions >
<ListView Name="lstCars" Grid.Row="0"ItemsSource=
"{Binding Source={StaticResource CarsXmlDoc}, XPath=/Inventory/Car}"
>
<ListView.View>
<GridView>
<GridViewColumn Width="100" Header="ID"
DisplayMemberBinding="{Binding XPath=@carID}"/>
<GridViewColumn Width="100" Header="Make"
DisplayMemberBinding="{Binding XPath=Make}"/>
<GridViewColumn Width="100" Header="Color"
DisplayMemberBinding="{Binding XPath=Color}"/>
<GridViewColumn Width="150" Header="Pet Name"
DisplayMemberBinding="{Binding XPath=PetName}"/>
</GridView>
</ListView.View>
</ListView>
<WrapPanel Grid.Row="1">

<Label Content="Select a Row to Add to your car collection" Margin="10" />
<Button Name="btnOK" Content="OK" Width="80" Height="25"
Margin="10" IsDefault="True" TabIndex="1" Click="btnOK_Click"/>
<Button Name="btnCancel" Content="Cancel" Width="80" Height="25"
Margin="10" IsCancel="True" TabIndex="2"/>
</WrapPanel>
</Grid>
</Window>
Starting at the top, notice that the opening <Window> element has been defined by specifying a
value of
NoResize to the ResizeMode attribute, given that most dialog boxes do not allow the user to
alter the size of the window’s dimensions.
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1113
8849CH29.qxd 10/16/07 12:17 PM Page 1113
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
Beyond carving up our <Grid> into two rows of a given size, the next point of interest is that we
are placing into the grid’s resource dictionary a new object of type
XmlDataProvider. This type can
be connected to an external
*.xml file (or an XML data island within the XAML file) via the Source
attribute. As we have configured the Inventory.xml file to be located within the application direc-
tory of our current project, we have no need to worry about hard-coding a fixed path.
The real bulk of this markup takes place within the definition of the
ListView type. First of all,
notice that the
ItemsSource attribute has been assigned to the CarsXmlDoc resource, which is quali-
fied using the
XPath attribute. Based on your experience, you may know that XPath is an XML
technology that allows you to navigate within an XML document using a query-like syntax. Here we

are saying that our initial data-binding path begins with the
<Car> element of the <Inventory> root.
To inform the
ListView type to display a grid-like front end, we next make use of the
<ListView.View> element to define a <GridView> consisting of four <GridViewColumns>. Each of these
types specifies a
Header value (for display purposes) and most importantly a DisplayMemberBinding
data-binding value. Given that the <ListView> itself has already specified the initial path within the
XML document to be the
<Car> subelement of <Inventory>, each of the XPath bindings for the col-
umn types use this as a starting point.
The first
<GridViewColumn> is displaying the ID attribute of the <Car> element using an XPath-
specific syntax for plucking our attribute values (
@caID). The remaining columns simply further
qualify the path within the XML document by appending the next subelement using the
XPath qual-
ifier of the
{Binding} markup extension.
Last but not least, the final row of the
<Grid> contains a <WrapPanel> that contains two Buttons
(and a descriptive
Label) to complete the UI. The only points of interest here would be that we are
handling the
Click event of the OK button and the use of the IsDefault and IsCancel properties.
These establish which button on a window should respond to the
Click event when the Enter key or
Esc key is pressed.
Finally, note that these
Button types specify a TabIndex value and a Margin value, the latter of

which allows you to define spacing around each item in the
<WrapPanel>.
Assigning the DialogResult Value
Before we display this new dialog box, we need to implement the Click handler for the OK button.
Similar to Windows Forms (see Chapter 27), WPF dialog boxes can inform the caller which button
has been clicked via the
DialogResult property. However, unlike the DialogResult property found in
Windows Forms, in the WPF model, this property operates on a nullable Boolean value, rather than
a strongly typed enumeration. Thus, if you wish to inform the caller the user wishes to employ the
data in the dialog box for use within the program (typically indicated by clicking an OK, a Yes, or an
Accept button), set the inherited
DialogResult property to true in the Click handler of said button:
private void btnOK_Click(object sender, RoutedEventArgs e)
{
DialogResult = true;
}
As the default value of DialogResult is false, we have no need to do anything if the user clicks
the Cancel button.
Obtaining the Current Selection
Finally, add a custom read-only property to your AddNewCarDialog named SelectedCar, which
returns a new
Car object to the caller based on the values of the selected row of the grid:
public Car SelectedCar
{
get
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1114
8849CH29.qxd 10/16/07 12:17 PM Page 1114
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
{

// Cast selected item on grid to an XmlElement.
System.Xml.XmlElement carRow =
(System.Xml.XmlElement)lstCars.SelectedItem;
// Make sure the user selected something!
if (carRow == null)
{
return null;
}
else
{
// Generate a random speed.
Random r = new Random();
int speed = r.Next(100);
// Return new Car based on the data in selected XmlElement/speed.
return new Car(speed, carRow["Make"].InnerText,
carRow["Color"].InnerText, carRow["PetName"].InnerText);
}
}
}
Notice we cast the return value of the SelectedItem property (which is of type System.Object)
into an
XmlElement type. This is possible because our ListView is indeed connected to the
Inventory.xml file via our data-binding operation. Once we nab the current XmlElement, we are able
to access the
Make, Color, and PetName elements (using the type indexer) and extract out the values
by calling
InnerText.
■Note If you have never worked with the types of the System.Xml namespace, simply know that the
InnerText property obtains the value between the opening and closing elements of an XML node. For example,
the inner text of <Make>Ford</Make> would be Ford.

Displaying a Custom Dialog Box
Now that our dialog box is complete, we are able to launch it from the Click handler of the File ➤
Add New Car menu option:
private void AddNewCarWizard(object sender, RoutedEventArgs e)
{
AddNewCarDialog dlg = new AddNewCarDialog();
if (true == dlg.ShowDialog())
{
if (dlg.SelectedCar != null)
{
myCars.Add(dlg.SelectedCar);
}
}
}
Like Windows Forms, a WPF dialog box may be shown as a modal dialog box (by calling
ShowDialog()) or as a modaless dialog (by calling Show()). If the return value of ShowDialog() is true,
we ask the dialog box for the new
Car object and add it to our ObservableCollection<T>. Because
this collection type sends out notifications when its contents are altered, you will find your
ListBox
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1115
8849CH29.qxd 10/16/07 12:17 PM Page 1115
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -
will automatically refresh itself as you insert new items. Figure 29-35 shows the UI of our custom
dialog box.
Figure 29-35. A custom grid of data, bound to an XML document
■Source Code The CarViewerApp project can be found under the Chapter 29 subdirectory.
That wraps up our look at the WPF data-binding engine and the core controls found within this
UI API. In the next chapter, you will complete your investigation of Windows Presentation Founda-

tion by examining the role of graphical rendering, resource management, and the construction of
custom themes.
Summary
This chapter examined several aspects of WPF controls, beginning with a discussion of dependency
properties and routed events. These WPF mechanisms are very important for several aspects of WPF
programming including data binding, animation services, and a slew of other features. Over the
course of this chapter, you have had a chance to configure and tweak several controls and learned
to arrange your UI content in various panel types.
More importantly, you examined the use of WPF commands. Recall that these control-agnostic
events can be attached to a UI element or an input gesture to automatically inherit out-of-the-box
services (such as clipboard operations). You also dove into the mechanics of the WPF data-binding
engine and learned how to bind property values, custom objects, and XML documents to your UI
layer. At this time, you also learned how to build WPF dialog boxes and discovered the role of the
IValueConverter and ObservableCollection<T> types.
CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1116
8849CH29.qxd 10/16/07 12:17 PM Page 1116
www.free-ebooks-download.org
Simpo PDF Merge and Split Unregistered Version -

×