<<

C H A T E R 2 7

■ ■ ■

Introducing Windows Presentation Foundation and XAML

When version 1.0 of the .NET platform was released, programmers who needed to build graphical desktop applications made use of two named and GDI+, packaged up primarily in the System.Windows.Forms.dll and System.Drawing.dll assemblies. While Windows Forms/GDI+ are excellent APIs for building traditional desktop GUIs, shipped an alternative GUI desktop API named Windows Presentation Foundation (WPF) beginning with the release of .NET 3.0. This initial WPF chapter begins by examining the motivation behind this new GUI framework, will help you see the differences between the Windows Forms/GDI+ and WPF programming models. Next, we will examine the different types of WPF applications supported by the API, and come to know the role of the several important classes including Application, , ContentControl, Control, UIElement, and FrameworkElement. During this time, you will learn to intercept keyboard and mouse activities, define application wide data, and other common WPF tasks using nothing but VB 2010 code. This chapter will then introduce you to an XML-based grammar named Extensible Application Markup Language (XAML). Here, you will learn the syntax and semantics of XAML, including attached property syntax, the role of converters, markup extensions, and understanding how to generate, load and parse XAML at runtime. As well, you will learn how to integrate XAML data into a VB 2010 WFP- code base (and the benefits of doing so). This chapter wraps up by the integrated WPF designers of Visual Studio 2010. Here, you will build your own custom XAML editor/parser, which illustrates how XAML can be manipulated at runtime to build dynamic user interfaces.

■ Note The remaining WPF chapters of this book will introduce you to Microsoft Expression Blend, which is a WPF-centric tool dedicated to the generation of XAML on your behalf.

The Motivation Behind WPF Over the years, Microsoft has created numerous toolkits (VB6, raw /C++/Windows API development, MFC, etc.) to build desktop executables. Each of these APIs provided a code base to represent the basic aspects of a GUI application, including main windows, dialog boxes,

1165 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

controls, menu systems, and other basic necessities. With the initial release of the .NET platform, the Windows Forms API quickly became the preferred model for UI development, given its simple yet very powerful object model. While many full-featured desktop applications have been successfully created using Windows Forms, the fact of the matter is that this programming model is rather asymmetrical. Simply put, System.Windows.Forms.dll and System.Drawing.dll do not provide direct support for many additional technologies required to build a feature-rich desktop application. To illustrate this point, consider the ad hoc nature of GUI development before the release of WPF (e.g., .NET 2.0; see Table 27-1).

Table 27-1. .NET 2.0 Solutions to Desired Functionalities

Desired Functionality .NET 2.0 Solution

Building windows with controls Windows Forms

2D graphics support GDI+ (System.Drawing.dll)

3D graphics support DirectX APIs

Support for streaming video Player APIs

Support for flow-style documents Programmatic manipulation of PDF files

As you can see, a Windows Forms developer must pull in types from a number of unrelated APIs and object models. While it is true that making use of these diverse APIs may look similar syntactically (it is just VB 2010 code, after all), you may also agree that each technology requires a radically different mind- set. For example, the skills required to create a 3D rendered animation using DirectX are completely different from those used to bind data to a grid. To be sure, it is very difficult for a Windows Forms programmer to master the diverse nature of each API.

■ Note Appendix A provides an introduction to Windows Forms and GDI+ application development.

Unifying Diverse APIs WPF (introduced with .NET 3.0) was purposely created to merge these previously unrelated programming tasks into a single unified object model. Thus, if you need to author a 3D animation, you have no need to manually program against the DirectX API (although you could), as 3D functionality is baked directly into WPF. To see how well things have cleaned up, consider Table 27-2, which illustrates the desktop development model ushered in as of .NET 3.0.

1166 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Table 27-2. .NET 3.0 Solutions to Desired Functionalities

Desired Functionality .NET 3.0 and Higher Solution

Building forms with controls WPF

2D graphics support WPF

3D graphics support WPF

Support for streaming video WPF

Support for flow-style documents WPF

The obvious benefit here is that .NET programmers now have a single, symmetrical API for all common GUI programming needs. Once you become comfortable with the functionality of the key WPF assemblies and the grammar of XAML, you'll be amazed how quickly you can create very sophisticated UIs.

Providing a Separation of Concerns via XAML Perhaps one of the most compelling benefits is that WPF provides a way to cleanly separate the look and feel of a Windows application from the programming logic that drives it. Using XAML, it is possible to define the UI of an application via XML markup. This markup (ideally generated using tools such as Microsoft Expression Blend) can then be connected to a managed code base to provide the guts of the program’s functionality.

■ Note XAML is not limited to WPF applications! Any application can use XAML to describe a tree of .NET objects, even if they have nothing to do with a visible user interface. For example, the Windows Workflow Foundation API uses a XAML-based grammar to define business processes and custom activities.

As you dig into WPF, you may be surprised how much flexibility “desktop markup” provides. XAML allows you to define not only simple UI elements (buttons, grids, list boxes, etc.) in markup, but also 2D and 3D graphical data, animations, data binding logic, and multimedia functionality (such as video playback). For example, defining a circular control that animates a company logo requires just a few lines of markup. As shown in Chapter 31, WPF controls can be modified through styles and templates, which allow you to change the overall look and feel of an application with minimum fuss and bother. Unlike Windows Forms development, the only compelling reason to build a custom WPF control is if you need to change the behaviors of a control (e.g., add custom methods, properties, or events; subclass an existing control to override Overridable members). If you simply need to change the look and feel of a control (again, such as a circular animated button), you can do so entirely through markup.

1167 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Providing an Optimized Rendering Model GUI toolkits such as Windows Forms, VB6, or MFC preformed all graphical rendering requests (including the rendering of UI elements such as buttons and list boxes) using a low level, API (GDI), which has been part of the Windows OS for years. GDI provides adequate performance for typical business applications or simple graphical programs; however, if a UI application needed to tap into high performance graphics, DirectX was required. The WPF programming model is quite different in that GDI is not used when rendering graphical data. All rendering operations (e.g., 2D graphics, 3D graphics, animations, UI widget renderings buttons, list boxes) now make use of the DirectX API. The first obvious benefit is that your WPF applications will automatically take advantage of hardware and software optimizations. As well, WPF applications can tap into very rich graphical services (blur effects, anti-aliasing, transparency, etc.) without the complexity of programming directly against the DirectX API.

■ Note Although WPF does push all rendering requests to the DirectX layer, I don't want to suggest that a WPF application will perform as fast as building an application using unmanaged C++ and DirectX directly. If you are build a desktop application that requires the fastest possible execution speed (such as a 3D video game), unmanaged C++ and DirectX are still the best approach.

Simplifying Complex UI Programming To recap the story thus far, Windows Presentation Foundation (WPF) is an API to build desktop applications that integrates various desktop APIs into a single object model and provides a clean separation of concerns via XAML. In addition to these major points, WPF applications also benefit from a very simple way to integrate services into your programs, which historically were quite complex to account for. Here is a quick rundown of the core WPF features: • A number of layout managers (far more than Windows Forms) to provide extremely flexible control over placement and reposition of content. • Use of an enhanced data-binding engine to bind content to UI elements in a variety of ways. • A built-in style engine, which allows you to define “themes” for a WPF application. • Use of vector graphics, which allows content to be automatically resized to fit the size and resolution of the screen hosting the application. • Support for 2D and 3D graphics, animations, and video and audio playback. • A rich typography API, such as support for XML Paper Specification (XPS) documents, fixed documents (WYSIWYG), flow documents, and document annotations (e.g., a Sticky Notes API). • Support for interoperating with legacy GUI models (e.g., Windows Forms, ActiveX, and Win32 HWNDs). For example, you can incorporate custom Windows Forms controls into a WPF application, and vice versa.

1168 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Now that you have some idea of what WPF brings to the table, let's turn our attention to the various types of applications that can be created using this API.

The Various Flavors of WPF The WPF API can be used to build a variety of GUI-centric applications that basically differ in their navigational structure and deployment models. The sections that follow present a high-level walk through each option.

Traditional Desktop Applications The first (and most familiar) option is to use WPF to build a traditional executable assembly that runs on a local machine. For example, you could use WPF to build a text editor, painting program, or multimedia program such as a digital music player, photo viewer, and so forth. Like any other desktop applications, these *.exe files can be installed using traditional means (setup programs, packages, etc.) or via ClickOnce technology to allow desktop applications to be distributed and installed via a remote web server. Programmatically speaking, this type of WPF application will make use (at a minimum) of the Window and Application types, in addition to the expected set of dialog boxes, , status bars, menu systems, and other UI elements. Now, you can certainly use WPF to build your basic, bland business application that does not support any bells and whistles, but WPF really shines when you do incorporate such features. Consider Figure 27-1, which shows a WPF sample desktop application for viewing patient records in a medical environment.

1169 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Figure 27-1. This WPF desktop application makes use of several WPF APIs

Sadly, the printed does not show the full feature set of this window. Note that the upper right of the main window is displaying a real time graph of the patient's sinus rhythm. If you click on Patient Details button on the lower right, several animations take place to flip, rotate and transform the UI to the following look and feel (Figure 27-2).

1170 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Figure 27-2. Transformations and animations are very simple under WPF

Could you build this same application without WPF? Absolutely. However, the amount of code— and the complexity of the code—would be much higher.

■ Note This example application can be downloaded (with source code) from the office WPF web site, http://windowsclient.net. Here you will find numerous WPF (and Windows Forms) sample projects, technology walkthroughs and forums.

1171 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Navigation-Based WPF Applications WPF applications can optionally choose to make use of a navigation-based structure, which makes a traditional desktop application take on the basic behavior of a web browser application. Using this model, you can build a desktop *.exe that provides a “forward” and “back” button that allows the end user to move back and forth between various UI displays called pages. The application itself maintains a list of each page and provides the necessary infrastructure to navigate between them, pass data across pages (similar to a web-based application variable), and maintain a history list. By way of a concrete example, consider Windows Explorer (see Figure 27-3), which makes use of such functionality. Notice the navigation buttons (and history list) mounted on the upper-left corner of the window.

Figure 27-3. A navigation-based desktop program

Regardless of the fact that a WPF desktop application can take on a weblike navigational structure, understand that this is simply a UI design issue. The application itself is still little more than a local executable assembly running on a desktop machine, and it has little to do with a web application beyond a slightly similar look and feel. Programmatically speaking, this type of WPF application is constructed using classes such as Application, Page, NavigationWindow, and Frame.

XBAP Applications WPF also allows you to build applications that can be hosted within a web browser. This flavor of WPF application is termed an XAML browser application, or XBAP. Under this model, the end user navigates to a given URL, at which point the XBAP (which is essentially a collection of Page objects) is transparently downloaded and installed to the local machine. Unlike a traditional ClickOnce installation for an executable application, however, the XBAP program is hosted directly within the browser and adopts the browser’s intrinsic navigational system. Figure 27-4 illustrates an XBAP program in action (specifically, the ExpenseIt WPF sample program that ships with the .NET Framework 4.0 SDK).

1172 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Figure 27-4. XBAP programs are downloaded to a local machine and hosted within a web browser

The benefit of an XBAP is that it allows you to create sophisticated UIs which are much more expressive than a typical web page built with HTML and JavaScript. An XBAP Page object can make use of the same WPF services as a desktop WPF application, including animations, 2D and 3D graphics, themes and whatnot. In effect, the web browser is just a container for WPF Page objects, and is not displaying ASP.NET web pages. However, given that these Page objects are deployed to a remote web server, XBAPs can be easily versioned and updated without the need to redeploy executables to the user's desktop. Like a traditional web program, you can simply update the Page objects in the web server, and the user will get the 'latest and greatest' when they access the URL. One downside to this flavor of WPF is that XBAPs must be hosted within Microsoft or Firefox web browsers. If you are deploying XBAPs across a company intranet, browser compatibility should not be a problem, given that system administrators can play dictator regarding which browser should be installed on users’ machines. However, if you want the outside world to make use of your XBAP, it is not possible to ensure each end user is making use of Internet Explorer/Firefox, and therefore some external users may not be able to view your WPF XBAP. Another issue to be aware of is the machine which is viewing an XBAP must have a local installation of the .NET framework, as the Page objects will be using the same .NET assemblies as an application running natively on the machine. Given this particular point, XBAPs are limited to Windows operating systems and thus cannot be viewed on a system running Mac OS X or Linux.

1173 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

The WPF/Silverlight Relationship WPF and XAML also provide the foundation for a cross-platform, cross-browser WPF-based technology termed Silverlight. From a high level, you can consider Silverlight as a competitor to , with the benefit of using VB 2010 and XAML rather than a new set of tools and languages. Silverlight is a subset of WPF functionality, which is used to build highly interactive plug-ins for a larger HTML-based web page. In reality, however, Silverlight is a completely unique distribution of the .NET platform, which ships with a "mini" CLR and "mini" version of the .NET base class libraries. Unlike an XBAP, the user's machine does not need a full installation of the .NET Framework. As long as the target machine has the Silverlight runtime installed, the browser will load the Silverlight runtime and display the Silverlight application automatically. Best of all, Silverlight plug-ins are not limited to the Windows operating systems! Microsoft has also created a Silverlight runtime for Mac OS X.

■ Note The project (see Appendix B) provides an open source version of Silverlight for Linux based OSs named . This API, in conjunction with Silverlight, provides the fabric for a true cross-platform model for extremely rich web pages.

With Silverlight, you are able to build extremely feature-rich (and interactive) web applications. For example, like WPF, Silverlight has a vector-based graphical system, animation support, and multimedia support. Furthermore, you are able to incorporate a subset of the .NET base class library into your applications. This subset includes a number of WPF controls, LINQ support, generic collection types, web service support, and a healthy subset of mscorlib.dll (file I/O, XML manipulation, etc.).

■ Note This edition of the text does not address Silverlight; however, a majority of your WPF knowledge will map directly to the construction of Silverlight web plug-ins. If you are interested in learning more about this API, check out www.silverlight.net.

Investigating the WPF Assemblies Regardless of which type of WPF application you wish to build, WPF is ultimately little more than a collection of types bundled within .NET assemblies. Table 27-3 describes the core assemblies used to build WPF applications, each of which must be referenced when creating a new project (as you would hope, Visual Studio 2010 and Expression Blend WPF projects automatically reference the required assemblies).

1174 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Table 27-3. Core WPF Assemblies

Assembly Meaning in Life

PresentationCore.dll This assembly defines numerous types that constitute the foundation of the WPF GUI layer. For example, this assembly contains support for the WPF Ink API (for programming against stylus input for Pocket PCs and Tablet PCs), several animation primitives, and numerous graphical rendering types.

PresentationFramework.dll This assembly contains a majority of the WPF controls, the Application and Window classes, and support for interactive 2D geometries. As well, this library provides basic functionality to read and write XAML documents at runtime.

System.Xaml.dll This assembly provides namespaces which allow you to program against a XAML document at runtime. By and large, this library is only useful if you are authoring WPF support tools or need absolute control over XAML at runtime.

WindowsBase.dll This assembly defines types that constitute the infrastructure of the WPF API., including those representing WPF threading types, security types, various type converters, and support for dependency properties and routed events (described in Chapter 29).

Collectively, these assemblies define a number of new namespaces and hundreds of new .NET classes, interfaces, structures, enumerations, and delegates. While you should consult the .NET Framework 4.0 SDK documentation for complete details, Table 27-4 describes the role of some (but certainly not all) of the namespaces you should be aware of.

Table 27-4. Core WPF Namespaces

Namespace Meaning in Life

System.Windows This is the root namespace of WPF. Here you will find core classes (such as Application and Window) that are required by any WPF desktop project.

System.Windows.Controls Contains all of the expected WPF widgets, including types to build menu systems, tool tips, and numerous layout managers.

System.Windows.Data Types to work with the WPF data binding engine, as well as support for data binding templates.

System.Windows.Documents Contains types to work with the documents API, which allows you to integrate PDF style functionality into your WPF applications, via the XML Paper Specification (XPS) protocol.

1175 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Continued

Namespace Meaning in Life

System.Windows.Ink Support for the Ink API, which allows you to capture input from a stylus or mouse, respond to input gestures, and so forth. Very useful for Tablet PC program; however, any WPF can make use of this API.

System.Windows.Markup This namespace defines a number of types that allow XAML markup (and the equivalent binary format, BAML) to be parsed and processed programmatically.

System.Windows.Media This is the root namespace to several media-centric namespaces. Within these namespaces you will find types to work with animations, 3D rendering, text rendering, and other multimedia primitives.

System.Windows.Navigation This namespace provides types to account for the navigation logic employed by XAML browser applications (XBAPs) as well as standard desktop applications that require a navigational page model.

System.Windows.Shapes Defines classes which allow you to render interactive 2D graphics that automatically respond to mouse input.

To begin your journey into the WPF programming model, you’ll examine two members of the System.Windows namespace that are commonplace to any traditional desktop development effort: Application and Window.

■ Note If you are new to the development of desktop applications using the .NET platform, be aware that the System.Windows.Forms.* and System.Drawing.* assemblies are not related to WPF! These libraries represent the original .NET GUI toolkit, Windows Forms (see Appendix A).

The Role of the Application Class The System.Windows.Application class represents a global instance of a running WPF application. This class supplies a Run() method (to the application), a series of events that you are able to in order to interact with the application’s lifetime (such as Startup and Exit), and a number of events that are specific to XAML browser applications (such as events that fire as a user navigates between pages). Table 27-5 details some of the key properties to be aware of.

1176 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Table 27-5. Key Properties of the Application Type

Property Meaning in Life

Current This Shared property allows you to gain access to the running Application object from anywhere in your code. This can be very helpful when a window or needs to gain access to the Application object that created it, typically to access application wide variables and functionality.

MainWindow This property allows you to programmatically get or set the main window of the application.

Properties This property allows you to establish and obtain data that is accessible throughout all aspects of a WPF application (windows, dialog boxes, etc.).

StartupUri This property gets or sets a URI that specifies a window or page to open automatically when the application starts.

Windows This property returns a WindowCollection type, which provides access to each window created from the that created the Application object. This can be very helpful when you wish to iterate over each open window of an application and alter its state (such as minimizing all windows).

Constructing an Application Class Any WPF application will need to define a class that extends Application. Within this class, you will define your program's entry point (the Main() method), which creates an instance of this subclass and typically handles the Startup and Exit events. You will build a full example project in just a moment, but here is a quick example:

'Define the global application object 'for this WPF program. Class MyApp Inherits Application _ Shared Sub Main(ByVal args As String()) ' Create the application object. Dim app As New MyApp()

' Register the Startup / Exit events. AddHandler app.Startup, AddressOf AppStartUp AddHandler app.Exit, AddressOf AppExit End Sub End Class

1177 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Within the Startup handler, you will most often any incoming command line arguments and launch the main window of the program. The Exit handler, as you would expect, is where you can author any necessary shut down logic for the program (e.g., save user preferences, write to the ).

Enumerating the Application.Windows collection Another interesting property exposed by Application is Windows, which provides access to a collection representing each window loaded into memory for the current WPF application. Recall that as you create new Window objects, they are automatically added into the Application.Windows collection. Here is an example method that will minimize each window of the application (perhaps in response to a given keyboard gesture or menu option triggered by the end user):

Private Shared Sub MinimizeAllWindows() For Each wnd As Window In Application.Current.Windows wnd.WindowState = WindowState.Minimized Next End Sub

You’ll build a complete Application-derived type in an upcoming example. Until then, let’s check out the core functionality of the Window type and learn about a number of important WPF base classes in the process.

The Role of the Window Class The System.Windows.Window class represents a single window owned by the Application-derived class, including any dialog boxes displayed by the main window. Not surprisingly, Window has a series of parent classes, each of which brings more functionality to the table. Consider Figure 27-5, which shows the inheritance chain (and implemented interfaces) for System.Windows.Window as seen through the Visual Studio 2010 object browser.

1178 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Figure 27-5. The hierarchy of the Window class

You’ll come to understand the functionality provided by many of these base classes as you progress through this chapter and the chapters to come. However, to whet your appetite, the following sections present a breakdown of the functionality provided by each base class (consult the .NET Framework 4.0 SDK documentation for full details).

The Role of System.Windows.Controls.ContentControl The direct parent of Window is ContentControl, which is quite possibly the most enticing of all WPF classes. This base class provides derived types with the ability to host a single piece of content, which, simply put, refers to the data placed within the interior of the control’s surface area via the Content property. The WPF content model makes it very simple to customize the basic look and feel of a content control. For example, when you think of a typical "button" control, you tend to assume that the content is a basic string literal (OK, Cancel, Abort, etc). If you are using XAML to describe a WPF control, and the value you wish to assign to the Content property can be captured as a simple string, you may set the Content property within the element’s opening definition as so (don't fret over the exact markup at this point):

You can also make use of XAML's property-element syntax to set complex content. Consider the following functionally equivalent

Do be aware that not every WPF control derives from ContentControl, and therefore not all controls supports this unique content model. As well, some WPF controls add a few refinements to the basic content model you have just examined. Chapter 28 will examine the role of WPF content in much more detail.

1180 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

The Role of System.Windows.Controls.Control Unlike ContentControl, all WPF controls share the Control base class as a common parent. This base class provides numerous core members that account for basic UI functionality. For example, Control defines properties to establish the control’s size, opacity, order logic, the display cursor, background color, and so forth. Furthermore, this parent class provides support for templating services. As explained in Chapter 31, WPF controls can completely change the way they render their appearance using templates and styles. Table 27-6 documents some key members of the Control type, grouped by related functionality.

Table 27-6. Key Members of the Control Type

Members Meaning in Life

Background, Foreground, BorderBrush, These properties allow you to set basic settings regarding how the BorderThickness, Padding, control will be rendered and positioned. HorizontalContentAlignment, VerticalContentAlignment

FontFamily, FontSize, FontStretch, These properties control various font-centric settings. FontWeight

IsTabStop, TabIndex These properties are used to establish tab order among controls on a window.

MouseDoubleClick, These events handle the act of double-clicking a widget. PreviewMouseDoubleClick

Template This property allows you to get and set the control’s , which can be used to change the rendering output of the widget.

The Role of System.Windows.FrameworkElement This base class provides a number of members that are used throughout the WPF framework, such as support for storyboarding (used within animations) and support for data binding, as well as the ability to name a member (via the Name property), obtain any resources defined by the derived type, and establish the overall dimensions of the derived type. Table 27-7 hits the highlights.

1181 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Table 27-7. Key Members of the FrameworkElement Type

Members Meaning in Life

ActualHeight, ActualWidth, MaxHeight, These properties control the size of the derived type. MaxWidth, MinHeight, MinWidth, Height, Width

ContextMenu Gets or sets the pop-up menu associated with the derived type.

Cursor Gets or sets the mouse cursor associated with the derived type.

HorizontalAlignment, VerticalAlignment Gets or sets how the type is positioned within a container (such as a panel or list box).

Name Allows to you assign a name to the type, in order to access its functionality in a code file.

Resources Provides access to any resources defined by the type (see Chapter 30 for an examination of the WPF resource system).

ToolTip Gets or sets the tool tip associated with the derived type.

The Role of System.Windows.UIElement Of all the types within a Window’s inheritance chain, the UIElement base class provides the greatest amount of functionality. The key task of UIElement is to provide the derived type with numerous events to allow the derived type to receive focus and process input requests. For example, this class provides numerous events to account for drag-and-drop operations, mouse movement, keyboard input, and stylus input (for Pocket PCs and Tablet PCs). Chapter 29 digs into the WPF event model in detail; however, many of the core events will look quite familiar (MouseMove, KeyUp, MouseDown, MouseEnter, MouseLeave, etc.). In addition to defining dozens of events, this parent class provides a number of properties to account for control focus, enabled state, visibility, and hit testing logic, as shown in Table 27-8.

1182 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Table 27-8. Key Members of the UIElement Type

Members Meaning in Life

Focusable, IsFocused These properties allow you to set focus on a given derived type.

IsEnabled This property allows you to control whether a given derived type is enabled or disabled.

IsMouseDirectlyOver, IsMouseOver These properties provide a simple way to perform hit-testing logic.

IsVisible, Visibility These properties allow you to work with the visibility setting of a derived type.

RenderTransform This property allows you to establish a transformation that will be used to render the derived type.

The Role of System.Windows.Media.Visual The Visual class type provides core rendering support in WPF, which includes hit testing of rendered data, coordinate transformation, and bounding box calculations. In fact, the Visual class interacts with the underlying DirectX subsystem to actually draw data on the screen. As examined in Chapter 29, WPF provides three possible manners in which you can render graphical data, each of which differs in terms of functionality and performance. Use of the Visual type (and its children, such as DrawingVisual) provides the most lightweight way to render graphical data, but it also entails the greatest amount of manual code to account for all the required services. Again, more details to come in Chapter 29.

The Role of System.Windows.DependencyObject WPF supports a particular flavor of .NET properties termed dependency properties. Simply put, this approach allows a type to compute the value of a property based on the value of other properties. In order for a type to participate in this new property scheme, it will need to derive from the DependencyObject base class. In addition, DependencyObject allows derived types to support attached properties, which are a form of dependency property very useful when programming against the WPF data-binding model as well as when laying out UI elements within various WPF panel types. The DependencyObject base class provides two key methods to all derived types: GetValue() and SetValue(). Using these members, you are able to establish the property itself. Other bits of infrastructure allow you to “register” who can use the dependency/attached property in question. While dependency properties are a key aspect of WPF development, much of the time their details are hidden from view. Chapter 29 dives further into the details of the “new” property type.

The Role of System.Windows.Threading.DispatcherObject The final base class of the Window type (beyond System.Object, which I assume needs no further explanation at this point in the book) is DispatcherObject. This type provides one property of interest, Dispatcher, which returns the associated System.Windows.Threading.Dispatcher object. The Dispatcher

1183 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

class is the entry point to the event queue of the WPF application, and it provides the basic constructs for dealing with concurrency and threading. By and large, this is a lower-level class that can be ignored by the majority of your WPF applications.

Building a WPF Application without XAML Given all of the functionality provided by the parent classes of the Window type, it is possible to represent a window in your application by either directly creating a Window object or using this class as the parent to a strongly typed descendent. Let’s examine both approaches in the following code example. Although most WPF applications will make use of XAML, doing so is entirely optional. Anything that can be expressed in XAML can be expressed in code and (for the most part) vice versa. If you wish, it is possible to build a complete WPF project using the underlying object model and procedural code. To illustrate, let’s create a minimal but complete application without the use of XAML using the Application and Window classes directly. Begin by creating a new Console Application named WpfAppAllCode (don't worry, you will use the Visual Studio WPF project template later in this chapter). Next, access the Project | Add Reference dialog box and add a reference to WindowsBase.dll, PresentationCore.dll, System.Xaml.dll and PresentationFramework.dll. Now, update your initial VB 2010 file with the following code, which creates a window of modest functionality:

' A simple WPF application, written without XAML. Imports System.Windows Imports System.Windows.Controls

' In this first example, you are defining a single class type to ' represent the application itself and the main window. Class Program Inherits Application

_ Public Shared Sub Main(ByVal args As String()) ' Handle the Startup and Exit events, and then run the application. Dim app As New Program() AddHandler app.Startup, AddressOf AppStartUp AddHandler app.Exit, AddressOf AppExit

' Fires the Startup event. app.Run() End Sub

Private Shared Sub AppExit(ByVal sender As Object, ByVal e As ExitEventArgs) MessageBox.Show("App has exited") End Sub

Private Shared Sub AppStartUp(ByVal sender As Object, ByVal e As StartupEventArgs) ' Create a Window object and set some basic properties. Dim mainWindow As New Window() mainWindow.Title = "My First WPF App!" mainWindow.Height = 200 mainWindow.Width = 300

1184 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

mainWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen mainWindow.Show() End Sub End Class

■ Note The Main() method of a WPF application must be attributed with the attribute, which ensures any legacy COM objects used by your application are thread-safe. If you do not annotate Main() in this way, you will encounter a runtime exception.

Note that the Program class extends the System.Windows.Application class. Within the Main() method, you create an instance of the application object and handle the Startup and Exit events using method group conversion syntax. Recall from Chapter 11 that this shorthand notation removes the need to manually specify the underlying delegates used by a particular event. Of course, if you wish, you can specify the underlying delegates directly by name. In the following modified Main() method, notice that the Startup event works in conjunction with the StartupEventHandler delegate, which can only point to methods taking an Object as the first parameter and a StartupEventArgs as the second. The Exit event, on the other hand, works with the ExitEventHandler delegate, which demands that the method pointed to take an ExitEventArgs type as the second parameter:

_ Public Shared Sub Main(ByVal args As String()) ' This time, specify the underlying delegates. Dim app As New Program() AddHandler app.Startup, AddressOf AppStartUp AddHandler app.Exit, AddressOf AppExit

' Fires the Startup event. app.Run() End Sub

In any case, the AppStartUp() method has been configured to create a Window object, establish some very basic property settings, and call Show() to display the window on the screen in a modeless fashion (the ShowDialog() method can be used to launch a modal dialog). The AppExit() method simply makes use of the WPF MessageBox class to display a diagnostic message when the application is being terminated. Before you compile and run the project, you may want to set the entry point of the application. To do so, go to the project’s properties and then select the Application tab. Select the Startup object drop- down, choose Sub Main from the list, and save the changes. Now if you run the project you will find a very simple main window that can be minimized, maximized, and closed. To spice things up a bit, you need to add some user interface elements. Before you do, however, you should refactor your code base to account for a strongly typed and well-encapsulated Window-derived class.

1185 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Creating a Strongly Typed Window Currently, the Application-derived class directly creates an instance of the Window type upon application startup. Ideally, you would create a class deriving from Window in order to encapsulate its appearance and functionality. Assume that you have created the following class definition within your current WpfAppAllCode application (if you place this class in a new VB 2010 file, be sure to import the System.Windows namespace):

Class MainWindow Inherits Window

Public Sub New(ByVal windowTitle As String, ByVal windowHeight As Integer, ByVal windowWidth As Integer) Me.Title = windowTitle Me.WindowStartupLocation = WindowStartupLocation.CenterScreen Me.Height = windowHeight Me.Width = windowWidth End Sub End Class

You can now update your Startup event handler to simply directly create an instance of MainWindow:

Private Shared Sub AppStartUp(ByVal sender As Object, ByVal e As StartupEventArgs) ' Create a MainWindow object. Dim wnd As New MainWindow("My better WPF App!", 200, 300) wnd.Show() End Sub

Once the program is recompiled and executed, the output is identical. The obvious benefit is that you now have a strongly typed window class to build upon.

■ Note When you create a Window (or Window-derived) object, it will automatically be added to the windows collection of the Application class (via some constructor logic found in the Window class itself). You can use the Application.Windows property to iterate over the list of Window objects currently in memory.

Creating a Simple User Interface Adding a UI element to a Window in VB 2010 code will involve the following basic steps: 1. Define a member variable to represent the control. 2. Configure the control’s look and feel upon Window construction. 3. Assign the control to the inherited Content property, or alternatively, as a parameter to the inherited AddChild() method.

1186 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Recall that the WPF control content model demands that the Content property is set only once. Of course, a Window that only contained a single UI control would be quite useless. Therefore, in almost every case, the "single piece of content" that is assigned to the Content property is, in reality, a layout manager, such as DockPanel, Grid, Canvas, or StackPanel. Within the layout manager, you can have any combination of internal controls, including other nested layout managers. (Read more on this aspect of WPF development in Chapter 28.) For now, you will add a single Button control to your Window derived class. When you click the button, you will close the current window, which will indirectly terminate the application, as you have no other windows in memory. Ponder the following update to the MainWindow class (be sure you have imported System.Windows.Controls to gain access to the Button class):

Class MainWindow Inherits Window

' Our UI element. Private btnExitApp As New Button()

Public Sub New(ByVal windowTitle As String, ByVal windowHeight As Integer, ByVal windowWidth As Integer) ' Configure button and set the child control. AddHandler btnExitApp.Click, AddressOf btnExitApp_Clicked btnExitApp.Content = "Exit Application" btnExitApp.Height = 25 btnExitApp.Width = 100

' Set the content of this window to a single button. Me.Content = btnExitApp

' Configure the window. Me.Title = windowTitle Me.WindowStartupLocation = WindowStartupLocation.CenterScreen Me.Height = windowHeight Me.Width = windowWidth Me.Show() End Sub

Private Sub btnExitApp_Clicked(ByVal sender As Object, ByVal e As RoutedEventArgs) ' close the window Me.Close() End Sub End Class

Notice that the Click event of the WPF Button works in conjunction with a delegate named RoutedEventHandler, which begs the question, what is a routed event? You’ll examine the details of the WPF event model in the next chapter; for the time being, simply understand that targets of the RoutedEventHandler delegate must supply an Object as the first parameter and a RoutedEventArgs as the second. In any case, once you recompile and run this application, you will find the customized window shown in Figure 27-6. Notice that your button is automatically placed in the dead center of the window’s client area; this is the default behavior when content is not placed within a WPF panel type.

1187 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Figure 27-6. A Simple WPF application writen in 100% VB 2010 code

Interacting with Application Level Data Recall that the Application class defines a property named Properties, which allows you to define a collection of name/value pairs via a type indexer. Because this indexer has been defined to operate on type System.Object, you are able to store any sort of item within this collection (including your custom classes), to be retrieved at a later time using a friendly moniker. Using this approach, it is simple to share data across all windows in a WPF application. To illustrate, you will update the current Startup event handler to check the incoming command- line arguments for a value named /GODMODE (a common cheat code for many PC video games). If you find this token, you will establish a Boolean value set to True within the properties collection of the same name (otherwise you will set the value to False). Sounds simple enough, but how are you going to pass the incoming command-line arguments (typically obtained from the Main() method) to your Startup event handler? One approach is to call the Shared Environment.GetCommandLineArgs() method. However, these same arguments are automatically added to the incoming StartupEventArgs parameter and can be accessed via the Args property. That being said, here is the first update to the current code base:

Private Shared Sub AppStartUp(ByVal sender As Object, ByVal e As StartupEventArgs) ' Check the incoming command-line arguments and see if they ' specified a flag for /GODMODE. Application.Current.Properties("GodMode") = False

For Each arg As String In e.Args If arg.ToLower() = "/godmode" Then Application.Current.Properties("GodMode") = True Exit For End If Next ' Create a MainWindow object. Dim wnd As New MainWindow("My better WPF App!", 200, 300) End Sub

Application-wide data can be accessed from anywhere within the WPF application. All you are required to do is obtain an access point to the global application object (via Application.Current) and investigate the collection. For example, you could update the Click event handler of the Button as so:

1188 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Private Sub btnExitApp_Clicked(ByVal sender As Object, ByVal e As RoutedEventArgs) ' Did user enable /godmode? If CBool(Application.Current.Properties("GodMode")) Then MessageBox.Show("Cheater!") End If

Me.Close() End Sub

With this, if the end user launches our program as follows:

WpfAppAllCode.exe /godmode he or she will see our shameful message box displayed when terminating the application.

■ Note Recall that you can supply command line arguments within Visual Studio. Simply double click on the Properties within Solution Explorer, click the Debug tab from the resulting editor, and enter /godmode within the "Command line arguments" editor.

Handling the Closing of a Window Object End users can shut down a window using numerous built-in system-level techniques (e.g., clicking the “X” close button on the window’s frame) or by indirectly calling the Close() method in response to some user interaction element (e.g., File ➤ Exit). In either case, WPF provides two events that you can intercept to determine if the user is truly ready to shut down the window and remove it from memory. The first event to fire is Closing, which works in conjunction with the CancelEventHandler delegate. This delegate expects target methods to take System.ComponentModel.CancelEventArgs as the second parameter. CancelEventArgs provides the Cancel property, which when set to True will prevent the window from actually closing (this is handy when you have asked the user if he really wants to close the window or if perhaps he would like to save his work first). If the user did indeed wish to close the window, CancelEventArgs.Cancel can be set to False. This will then cause the Closed event to fire (which works with the System.EventHandler delegate), making it the point at which the window is about to be closed for good. Update the MainWindow class to handle these two events by adding these code statements to the current constructor:

Public Sub New(ByVal windowTitle As String, ByVal windowHeight As Integer, ByVal windowWidth As Integer) ... AddHandler Me.Closing, AddressOf MainWindow_Closing AddHandler Me.Closed, AddressOf MainWindow_Closed End Sub

1189 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Now, implement the corresponding event handlers as so:

Private Sub MainWindow_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) ' See if the user really wants to shut down this window. Dim msg As String = "Do you want to close without saving?" Dim result As MessageBoxResult = MessageBox.Show(msg, "My App", MessageBoxButton.YesNo, MessageBoxImage.Warning)

If result = MessageBoxResult.No Then ' If user doesn't want to close, cancel closure. e.Cancel = True End If End Sub

Private Sub MainWindow_Closed(ByVal sender As Object, ByVal e As EventArgs) MessageBox.Show("See ya!") End Sub

Now, run your program and attempt to close the window, either by clicking the "X" icon on the upper right of the window or by clicking the button control. You should see the following confirmation dialog (Figure 27-7).

Figure 27-7. Trapping the Closing event of a Window

If you click the button, the application will terminate; however, clicking the No button will keep the window in memory.

Intercepting Mouse Events The WPF API provides a number of events you can capture in order to interact with the mouse. Specifically, the UIElement base class defines a number of mouse-centric events such as MouseMove, MouseUp, MouseDown, MouseEnter, MouseLeave, and so forth. Consider, for example, the act of handling the MouseMove event. This event works in conjunction with the System.Windows.Input.MouseEventHandler delegate, which expects its target to take a System.Windows.Input.MouseEventArgs type as the second parameter. Using MouseEventArgs (like a Windows Forms application), you are able to extract out the (x, y) position of the mouse and other relevant details. Consider the following partial definition:

1190 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Public Class MouseEventArgs Inherits InputEventArgs

... Public Function GetPosition(ByVal relativeTo As IInputElement) As Point Public ReadOnly Property LeftButton() As MouseButtonState Public ReadOnly Property MiddleButton() As MouseButtonState Public ReadOnly Property MouseDevice() As MouseDevice Public ReadOnly Property RightButton() As MouseButtonState Public ReadOnly Property StylusDevice() As StylusDevice Public ReadOnly Property XButton1() As MouseButtonState Public ReadOnly Property XButton2() As MouseButtonState End Class

■ Note The XButton1 and XButton2 properties allow you to interact with "extended mouse buttons" (such as the "next" and "previous" buttons found on some mouse controls). These are often used to interact with a browser's history list to navigate between visited pages.

The GetPosition() method allows you to get the (x, y) value relative to a UI element on the window. If you are interested in capturing the position relative to the activated window, simply pass in this. Handle the MouseMove event in the constructor of your MainWindow class like so:

Public Sub New(windowTitle As String, windowHeight As Integer, windowWidth As Integer) ... AddHandler Me.MouseMove, AddressOf MainWindow_MouseMove End Sub

Here is an event handler for MouseMove that will display the location of the mouse in the window’s title area (notice you are translating the returned Point type into a text value via ToString()):

Private Sub MainWindow_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) ' Set the title of the window to the current X,Y of the mouse. Me.Title = e.GetPosition(Me).ToString() End Sub

Intercepting Keyboard Events Processing keyboard input is also very straightforward. UIElement defines a number of events that you can capture to intercept keypresses from the keyboard on the active element (e.g., KeyUp, KeyDown). The KeyUp and KeyDown events both work with the System.Windows.Input.KeyEventHandler delegate, which expects the target’s second event handler to be of type KeyEventArgs, which defines several public properties of interest:

1191 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Public Class KeyEventArgs Inherits KeyboardEventArgs

... Public ReadOnly Property IsDown() As Boolean Public ReadOnly Property IsRepeat() As Boolean Public ReadOnly Property IsToggled() As Boolean Public ReadOnly Property IsUp() As Boolean Public ReadOnly Property Key() As Key Public ReadOnly Property KeyStates() As KeyStates Public ReadOnly Property SystemKey() As Key End Class

To illustrate, handle the KeyDown event in the constructor of MainWindow (just like you did for the previous events) and implement the following event handler that changes the content of the button with the currently pressed key, use this code:

Private Sub MainWindow_KeyDown(sender As Object, e As System.Windows.Input.KeyEventArgs) ' Display key press on the button. btnExitApp.Content = e.Key.ToString() End Sub

As a finishing , double click on the Properties icon of the Solution Explorer, and under the Application tab, set the Output Type setting to Windows Application. This will prevent the console window from launching in the background of your WPF application. Figure 27-8 shows the final product of your first WPF program.

Figure 27-8. Your first WPF program, 100% XAML free

At this point in the chapter, WPF might look like nothing more than yet another GUI framework that is providing (more or less) the same services as Windows Forms, VB6, or MFC. If this were in fact the case, you might question the need for yet another UI toolkit. To truly see what makes WPF so unique requires an understanding of the XML-based grammar, XAML.

■ Source Code The WpfAppAllCode project is included under the Chapter 27 subdirectory.

1192 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Building a WPF Application using Only XAML A typical WPF application will not be composed exclusively of code, as you did in this first example. Rather, your VB 2010 code files will be paired with a related XAML source file, and together they represent the entirety of a given Window or Application, as well as other class types we have not yet examined such as UserControl and Page. This approach is termed the code file approach to building a WPF application, and you will make use of this technique extensively throughout the remainder of the books WPF coverage. However, before you do, the next example will illustrate how to build a WPF application using nothing but XAML files. While this "100% XAML" approach is not recommended, it will help you clearly understand how blobs of markup are transformed into a corresponding VB 2010 code base, and ultimately, a .NET assembly.

■ Note This next example will make use of a number of XAML techniques we have not yet formally examined, so don't sweat the details. You may wish to simply load the solution files into a text editor and follow along; however, don't use Visual Studio 2010 to do so! Some of the markup in this sample contains markup that cannot be displayed in the Visual Studio XAML designers.

In general, XAML files will contain markup that describes the look and feel of the window , while the related VB 2010 code files contain the implementation logic. For example, the XAML file for a Window might describe the overall layout system, the controls within that layout system, and specify the names of various event handlers. The related VB 2010 file would contain the implementation logic of these event handlers and any custom code required by the application. Extensible Application Markup Language, or XAML, is an XML-based grammar that allows you to define the state (and, to some extent, the functionality) of a tree of .NET objects through markup. While XAML is frequently used when building UIs with WPF, in reality it can be used to describe any tree of nonabstract .NET types (including your own custom types defined in a custom .NET assembly), provided each supports a default constructor. As you will see, the markup within a *.xaml file is transformed into a full-blown object model. Because XAML is an XML-based grammar, we gain all the benefits and drawbacks XML affords us. On the plus side, XAML files are very self-describing (as any XML document should be). By and large, each element in an XAML file represents a type name (such as Button, Window, or Application) within a given .NET namespace. Attributes within the scope of an opening element map to properties (Height, Width, etc.) and events (Startup, Click, etc.) of the specified type. Given the fact that XAML is simply a declarative way to define the state of an object, it is possible to define a WPF widget via markup or procedural code. For example, the following XAML

You should now see your page render at the upper part of the kaxaml editor (Figure 27-13).

Figure 27-13. Kaxaml is a very helpful (and free) tool used to learn the grammar of XAML

As you work with kaxaml, remember that this tool does not allow you to author any markup that entails code compilation (however, using x:Name is allowed). This includes defining a x:Class attribute (for specifying a code file), entering event handler names in markup, or using any XAML keywords that also entail code compilation (such as FieldModifier or ClassModifier). Any attempt to do so will result in a markup error.

XAML XML Namespaces and XAML "Keywords" The root element of a WPF XAML document (such as a , , or definition) will almost always make reference to two predefined XML namespaces:

1204 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

The first XML namespace, http://schemas.microsoft.com/winfx/2006/xaml/presentation, maps a slew of WPF .NET namespaces for use by the current *.xaml file (System.Windows, System.Windows.Controls, System.Windows.Data, System.Windows.Ink, System.Windows.Media, System.Windows.Navigation, etc.). This one-to-many mapping is actually hard-coded within the WPF assemblies (WindowsBase.dll, PresentationCore.dll, and PresentationFramework.dll) using the assembly-level attribute. Here is one such listing, which essentially imports System.Windows:

If you load these WPF assemblies into reflector.exe, you can view these mappings firsthand. For example, if you select the PresentationCore.dll assembly (see Figure 27-14), and press the Space key, you will see numerous instances of the attribute.

Figure 27-14. The http://schemas.microsoft.com/winfx/2006/xaml/presentation namespace maps to the core WPF namespaces

1205 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

The second XML namespace, http://schemas.microsoft.com/winfx/2006/xaml, is used to include XAML-specific "keywords" (for lack of a better term) as well as the inclusion of the System.Windows.Markup namespace:

One rule of any well-formed XML document (remember, XAML is an XML-based grammar) is that the opening root element designates one XML namespace as the primary namespace, which typically is the namespace that contains the most commonly used items. If a root element requires the inclusion of additional secondary namespaces (as seen here), they must be defined using a unique tag prefix (to resolve any possible name clashes). As a convention, the prefix is simply x; however, this can be any unique token you require, such as XamlSpecificStuff:

The obvious downside of defining wordy XML namespace prefixes is you would be required to type XamlSpecificStuff each time your XAML file needs to refer to one of the items defined within this XAML-centric XML namespace . Given that XamlSpecificStuff requires many additional keystrokes, just stick with x. In any case, beyond the x:Name, x:Class and x:Code keywords, the http://schemas.microsoft. com/winfx/2006/xaml XML namespace also provides access to additional XAML keywords, the most common of which are shown in Table 27-9.

Table 27-9. XAML Keywords

XAML Keyword Meaning in Life

x:Array Represents a .NET array type in XAML.

x:ClassModifier Allows you to define the visibility of the VB 2010 class (Friend or Public) denoted by the Class keyword.

x:FieldModifier Allows you to define the visibility of a type member (Friend, Public, Private, or Protected) for any named subelement of the root (e.g., a

Notice that within the scope of the tags, you have defined a sub-scope named . Within this scope, you have defined a custom . (Don't worry about the exact code for the brush; you'll learn about WPF graphics in Chapter 30.)

1209 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Generally speaking, any property can be set using property-element syntax, that always breaks down to the following pattern:

While any property could be set using this syntax, if you can capture a value as a simple string, you will save yourself typing time. For example, here would be a much more verbose way to set the Width of your Button:

Understanding XAML Attached Properties In addition to property-element syntax, XAML defines a special syntax used to set a value to an attached property. Essentially, an attached property allows a child element to set the value for a property that is actually defined in a parent element. The general template to follow looks like this:

The most common use of attached property syntax is to position UI elements within one of the WPF layout managers classes (Grid, DockPanel, etc.). The next chapter dives into these panels in some detail; for now, enter the following in kaxaml:

Here, you have defined a Canvas layout manager that contains an Ellipse. Notice that the Ellipse is able to inform its parent (the Canvas) where to position its top/left position using attached property syntax. There are a few items to be aware of regarding attached properties. First and foremost, this is not an all-purpose syntax that can be applied to any property of any parent. For example, the following XAML cannot be parsed without error:

1210 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

In reality, attached properties are a specialized form of a WPF-specific concept termed a dependency property. Unless a property was implemented in a very specific manner, you cannot set its value using attached property syntax. You will explore dependency properties in a detail in Chapter 31.

■ Note Kaxaml, Visual Studio 2010, and Expression Blend all have IntelliSense, which will show you valid attached properties that can be set by a given element.

Understanding XAML Markup Extensions As explained, property values are most often represented using a simple string or via property-element syntax. There is, however, another way to specify the value of a XAML attribute, using markup extensions. Markup extensions allow a XAML parser to obtain the value for a property from a dedicated, external class. This can be very beneficial, given that some property values require a number of code statements to execute to figure out the value. Markup extensions provide a way to cleanly extend the grammar of XAML with new functionality. A markup extension is represented internally as a class that derives from MarkupExtension. Note that the chances of your ever needing to build a custom markup extension will be slim to none. However, a subset of XAML keywords (such as x:Array, x:Null, x:Static, and x:Type) are markup extensions in disguise! A markup extension is sandwiched between curly brackets, like so:

To see a markup extension in action, author the following into kaxaml:

1211 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Sun Kil Moon Red House Painters Besnard Lakes

First of all, notice that the definition has a new XML namespace declaration, which allows you to gain access to the System namespace of mscorlib.dll. With this XML namespace established, you first make use of the x:Static markup extension and grab values from OSVersion and ProcessorCount of the System.Environment class.

■ Note As you know, class-level members are called shared members in the vernacular of VB 2010. In terms of XAML, however, shared members are called static, and, therefore, we must use the {x:Static} token.

The x:Type markup extension allows you to gain access to the metadata description of the specified item. Here, you are simply assigning the fully qualified names of the WPF Button and System.Boolean types. The most interesting part of this markup is the ListBox. Here, you are setting the ItemsSource property to an array of strings declared entirely in markup! Notice how the x:Array markup extension allows you to specify a set of sub-items within its scope:

Sun Kil Moon Red House Painters Besnard Lakes

■ Note The previous XAML example is only used to illustrate a markup extension in action. As you will see in Chapter 28, there are much easier ways to populate ListBox controls!

1212 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

Figure 27-15 shows the mark up of this in kaxaml.

Figure 27-15. Markup extensions allow you to set values via the functionality of a dedicated class

So! At this point, you have seen numerous examples that showcase each of the core aspects of XAML syntax. As you might agree, XAML is very interesting in that it allows you to describe a tree of .NET objects in a declarative manner. While this is extremely helpful when configuring graphical user interfaces, do remember that XAML can describe any type from any assembly provided it is a nonabstract type containing a default constructor.

Building a WPF Application using Code-Behind Files The first two examples of this chapter illustrated the extreme ends of building a WPF application, using all code or using all XAML. The recommended way to build any WPF application, however, is to use the code file approach. Under this model, the XAML files of your project contain nothing but the markup that describes the general state of your classes, while the code file contains the implementation details.

Adding a Code File for the MainWindow Class To illustrate, you will update the WpfAppAllXaml example to use code files. If you are following along, copy this entire folder and give it the name WpfAppCodeFiles. Now, create a new VB 2010 code file in this folder named MainWindow.xaml.vb (by convention, the name of a VB 2010 code-behind file takes the form *.xaml.vb). Add the following code to this new file:

1213 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

' MainWindow.xaml.vb Class MainWindow

Private Sub btnExitApp_Clicked(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Me.Close() End Sub End Class

Here, you have defined a partial class to contain the event handling logic that will be merged with the partial class definition of the same type in the *.g.vb file. Given that InitializeComponent() is defined within the MainWindow.g.vb file, your window’s constructor makes a call in order to load and process the embedded BAML resource. The MainWindow.xaml file will also need to be updated; this simply involves gutting all traces of the previous VB 2010 code:

1219 CHAPTER 27 ■ INTRODUCING WINDOWS PRESENTATION FOUNDATION AND XAML

If you wish to handle events for a given control, you can also make use of the Properties window, but this time you need to click on the Events tab. Ensure that the button is selected on your designer, click on the Events tab, and locate the Click event. Once you do, double click directly on the Click event entry. This will cause Visual Studio 2010 to automatically build an event handler that takes the form:

NameOfControl_NameOfEvent

Since you did not rename your button, the Properties window shows it generated an event handler named button1_Click (see Figure 27-21).

Figure 27-21. Handling events using the visual designer

As well, Visual Studio 2010 generated the corresponding VB 2010 code in your window's code file. Here, you can add any sort of code that must execute when the button is clicked:

Class MainWindow Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles button1.Click

End Sub End Class

You can also handle events directly in the XAML editor. By way of an example, place your mouse within the