Chapter 18. WPF

First, there was plain-old Win32: C interfaces and a lot of work to get anything done. MFC wrapped up some of the complexity into an object-oriented framework, but it was a fairly thin layer on top of Win32. .NET’s Windows Forms was a more elegant attempt at abstracting away the old C interfaces, but they were still there somewhere.

Windows Presentation Foundation (WPF) throws all of that away and gives you a completely new framework from which to build user interfaces. It is designed to be hardware-accelerated to take advantage of today’s modern graphics cards.

As with any new framework, there is a lot to learn. However, especially in the case of WPF, the payoff is huge. You can do things in WPF with little effort that would previously require you to learn a specialized graphics API, such as DirectX.

WPF is nearly boundless in the amount you could learn, but the examples and tips in this chapter will get you well on your way to creating astounding interfaces in far less time than with the older framework.

Show a Window

Solution: Although most things in WPF can be expressed as either XAML or code, most examples will use XAML as much as possible.

Here’s the code in Window1.xaml:

image

The corresponding code in Window1.xaml.cs is even simpler:

image

The base Windows class’s InitializeComponent method will do the XAML parsing and present the window.

This and the next few sections build up a simple WPF-based text editor, complete with menu, toolbar, status bar, and commands.

Choose a Layout Method

Solution: WPF is all about automatic layout. You should rarely need to manually position UI elements. This makes it much easier to deal with dynamic content and internationalization, for example. WPF provides a number of layout controls for you, which are detailed in Table 18.1. You should rarely need to build your own.

Table 18.1 WPF Layout Controls

image

Nearly any interface can be composed of combinations of these layouts. The examples in this chapter use Grid, StackPanel, and DockPanel.

Add a Menu Bar

Solution: Many WPF examples show off the 3D capabilities, or its advanced data-binding features, but WPF excels at standard interfaces (menu bar, toolbar, status bar) just as easily, so we’ll start there before moving on to the more “wow” capabilities.

Let’s add a simple menu definition to the bare window:

image

Note

Note the underscores (_) in front of some of the letters in the menu. These indicate that the following character should be a shortcut character. In Win32-style programming, you would use an ampersand (&), but that has a special meaning in XML (of which XAML is derivative), so the underscore is used instead.

This menu doesn’t really do anything except be visible, so let’s add a few more UI elements and then hook everything up with commands.

Add a Status Bar

Solution: The StatusBar can easily be docked to the bottom of the DockPanel, as shown in this example:

image

The StatusBar contains a TextBlock that binds to the Text’s Length property of the TextBox. Data binding is discussed later in this chapter.

Note

One of the great powers of WPF is that because it’s not tied to Win32 in any way, you have a lot more freedom over layout. You can make your StatusBar contain a button, a menu, or a custom control if you want. The layout system is completely flexible. You can embed text boxes in buttons, and movies into check boxes (if you wanted to do such an odd thing), among many, many other things.

Add a Toolbar

Solution: Toolbars are the same concept as in Windows Forms but come with the flexibility inherent in all WPF controls:

image

The toolbar is docked to the top, and because it comes after the menu, it will appear right below it.

Use Standard Commands

Solution: WPF ships with a number of standard command handlers that work with the standard controls. For example, associating a Copy menu item with the built-in Copy command automatically enables the command when the focus is in a TextBox.

image

Use Custom Commands

Solution: Commands are commonly grouped into static classes for easy reference. Here, we define two commands:

image

These commands can now be used in command bindings and attached to event handlers:

image

And the XAML to hook them up is as follows:

image

Our nearly complete application, shown in Figure 18.1, requires little effort to implement but demonstrates some of WPF’s powerful techniques, such as data binding and commands.

Figure 18.1 Our nearly complete application.

image

Enable and Disable Commands

Solution: To complete this basic editor, let’s give it the dubious feature of disabling the Exit command if text has been entered (see Figure 18.2).

image

Figure 18.2 Disabling a command automatically grays out menu items and disables toolbar buttons.

image

Expand and Collapse a Group of Controls

Solution: An Expander is similar to a GroupBox in that it lets you group related elements under a common header. An Expander, however, also allows you to collapse the group to save UI space.

Here is one of the Expander elements from the ImageViewer sample app (see Figure 18.3):

image

Figure 18.3 An Expander element allows you to easily group and hide related child elements.

image

Respond to Events

Solution: The ImageViewer example defines two RadioButton elements. The RadioButton class has a Checked event. To assign an event handler in XAML, you can merely assign the name of the function to the event’s name:

image

The event handler looks quite similar to ones in standard .NET event handling:

image

Note

WPF elements use RoutedEvents, which are like regular .NET events with a bunch of features added onto them. They are required because WPF elements can have many layers of embedding. For example, if you embed a StackPanel, a TextBlock, and an Image inside a button and you click on the image, you still want it to seem to your application like a button was clicked, not the image.

RoutedEvents come in a few flavors: direct, bubbling, and tunneling.

Direct events are similar to .NET events: Only the source element itself can call event handlers.

Bubbling events are the most common in the WPF UI. The event starts with the source element and “bubbles” up to its parent, and its parent in turn, and so on.

Tunneling events start at the element root and travel downward to the source element.

Separate Look from Functionality

Solution: The Web introduced the concept of separating visual style from functionality to many developers. WPF uses the same idea with its powerful style system.

Styles are resources that can be defined in dedicated resource files or in an element’s own resource section.

image

This simple style merely sets the FontSize property of a Label to 12.

Note

Because the Style in this example specifies a TargetType but does not specify a name, it applies to all Label elements in its scope. You could alternatively name the style with <Style x:Key="MyStyle" ... /> and apply it to a specific Label with <Label Style="{StaticResource MyStyle}" ... />.

Use Triggers to Change Styles at Runtime

Solution: Triggers are a powerful functionality that can cause certain things to happen when events occur or data changes. They can be used in particular with styles to cause visual changes in response to the user’s input.

This example modifies the same Label style as before to change the look when the user hovers the mouse over it (see Figure 18.4).

image

Figure 18.4 You can use triggers to cause visual changes to appear in response to user actions.

image

Bind Control Properties to Another Object

Solution: We already have some simple data binding in the preceding examples. It is, in fact, hard to do WPF without using data binding, because that is what it naturally wants to do.

For binding to work, the binding must be associated with a DataContext. Elements search up their parent tree for the closest DataContext. Data binding is relative to that, unless explicitly stated otherwise (using ElementName or RelativeSource).

For the ImageViewer sample application, a data object was created specifically for data binding and set to the window’s DataContext.

Listings 18.1 and 18.2 demonstrate data binding with a drag-and-drop image viewer. Every time an image is dropped on the application, a new ImageInfoViewModel is created and assigned to the window’s DataContext property. The view model abstracts away the actual model (the image) and presents a simple class that can be used in data binding for the UI. For more on the view model and the overall design pattern here, see Chapter 25, “Application Patterns and Tips.”

Listing 18.1 ImageInfoViewModel.cs

image

image

image

Listing 18.2 Window1.xaml.cs

image

image

image

image

Here’s a part of the XAML that binds elements to the ImageInfoViewModel object:

image

Every time you drag an image onto the ImageViewer application, the UI will update with information about that image automatically when the ImageInfo property is set.

Format Values During Data Binding

Solution: Starting in .NET 3.5 SP1, you can use the StringFormat property.

image

Convert Values to a Different Type During Data Binding

Solution: Define a converter class derived from IValueConverter and implement one or both methods:

image

In your window XAML, define a resource and specify the converter where needed. In the following example, the background color is bound to the filename with this converter so that it becomes red if the filename is null:

image

Bind to a Collection

Solution: Binding to a collection of items is fairly straightforward. You can declare XAML like this:

image

However, because WPF doesn’t know how to display each item in the collection, it’s just going to call ToString() on each item. To customize the display, you need to define a data template, which is covered in the next section.

Specify How Bound Data Is Displayed

Solution: You can use a data template. Data templates are defined as resources:

image

Then modify the ListBox’s ItemTemplate property to refer to it:

image

The result is an attractive display of an arbitrary number of collection items, as previously seen in Figure 18.4.

Define the Look of Controls with Templates

Solution: If you look closely at Figures 18.3 and 18.4, you’ll see that the latter shows a caption under the image, whereas the former does not. This is accomplished with control templates.

The two ControlTemplates are defined, as usual, in the resources:

image

And the default template is set in the element’s definition:

image

An event handler (discussed previously) on the radio buttons causes the template to be switched:

image

Animate Element Properties

Solution: As far as WPF is concerned, animation is the change of an element’s properties over time. For example, you could change the x position of a button from 1 to 100 over, say, 5 seconds. This would have the effect of moving the button on the screen during that time. You can animate any dependency property in WPF.

The ImageViewer application uses a single animation to fade in the left-side panel over 5 seconds when the application starts. Figure 18.5 shows the application with it faded in about halfway.

Figure 18.5 This image shows the sidebar fading in during program startup.

image

First, define the storyboard with animation in the Window’s resources:

image

Once the animation is defined, you need to start with a trigger:

image

Render 3D Geometry

Solution: Starting in this section, you’ll see that WPF provides the unprecedented ability to merge 3D graphics with standard user interface elements and multimedia.

Effectively using 3D graphics requires learning a little about cameras, lighting, materials, and coordinate systems. Thankfully, WPF makes a lot of this very easy.

This simple demonstration creates a cube, complete with color and lighting, as seen in Figure 18.6

Figure 18.6 This cube demonstrates simple lighting and texture usage.

image

First, the geometry needs to be defined. For our simple examples, the shapes will be defined in the Window.Resources sections. Here is the definition for the six faces of the cube:

image

The actual placement of these mesh geometries is done inside a Viewport3D element:

image

image

image

Put Video on a 3D Surface

Solution: A plain-old cube is great, but what about one of those cube faces playing a movie (or showing an image, or any other WPF element)? Now, that is pretty cool. WPF makes this almost too easy.

image

image

image

image

The movie can be loaded into the MediaElement with code like this:

mediaPlayer.Source = new Uri(filename);
mediaPlayer.Play();

In the next section, we’ll hook it up to some controls, also in 3D.

Note

Yes, the ability to do this kind of stuff is pretty neat, but don’t go overboard. A movie pasted on to a 3D surface might make sense as part of a presentation, in a store kiosk, or perhaps as supporting material or as an animation to bring the movie to the foreground, but it’s probably not the best scenario for watching a whole movie. Just because you can do something doesn’t always mean you should.

Put Interactive Controls onto a 3D Surface

Solution: For that, Microsoft has released 3D Tools for Windows Presentation Foundation, available at http://3dtools.codeplex.com/. This package includes objects that wrap around WPF elements and translate the 3D environment into something the elements can understand.

In this example, let’s add some file selection and playback controls to our crazy video player (see Figure 18.7). You will also need to add a reference to the 3DTools.dll assembly in your project.

Figure 18.7 A cube playing a slideshow video, with working controls. I dare you to try this in Windows Forms.

image

Here is the complete code:

image

image

image

image

The code-behind provides the button functionality:

image

Use WPF in a WinForms App

Solution: You can easily interoperate between Windows Forms and WPF with the ElementHost control.

image

Figure 18.8 shows a Windows Forms application with a standard WinForms control and a WPF control. (It’s a button with a Label and TextBox in it just to prove it’s really WPF.)

Figure 18.8 A provably WPF control inside a Windows Forms application.

image

Use WinForms in a WPF Application

Solution: It’s just as easy to go the other direction.

image

Note that there is no NumericUpDown control in WPF (see Figure 18.9).

Figure 18.9 No NumericUpDown control in WPF. (Yet, we hope.)

image

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset