Chapter 1. Introducing WPF

In This Chapter

  • Taking a first look at WPF and what it can do for you

  • Working with XAML

  • Building your first WPF application

  • Comparing XAML to C#

WPF, or Windows Presentation Foundation, is a graphical system for rendering user interfaces. It provides great flexibility in how you can lay out and interact with your applications. With Common Language Runtime (CLR) at its core, you can use C# or any other CLR language to communicate with user interface elements and develop application logic. The advantages of WPF for your application are its rich data binding and visualization support and its design flexibility and styling.

WPF enables you to create an application that is more usable to your audience. It gives you the power to design an application that would previously take extremely long development cycles and a calculus genius to implement. Now you can implement difficult things like graphics and animations in as few as three lines of code!

This chapter introduces you to key WPF concepts as well as common application patterns used in the software industry today.

Understanding What WPF Can Do

WPF's graphics capabilities make it the perfect choice for data visualization. Take, for instance, the standard drop-down list (or combo box). Its current use is to enable the user to choose a single item from a list of items. For this example, suppose we want the user to select a car model for purchase.

The standard way of displaying this choice is to display a drop-down list of car model names from which users can choose. There is a fundamental usability problem with this common solution: Users are given only a single piece of information from which to base their decision — the text that is used to represent the item in the list.

For the power user (or car fanatic) this may not be an issue, but other users need more than just a model name to make an educated decision on the car they wish to purchase. This is where WPF and its data visualization capabilities come into play.

A template can be provided to define how each item in the drop-down list is rendered. The template can contain any visual element, such as images, labels, text boxes, tooltips, drop shadows, and more!

Figure 1-1 shows a typical display of a combo box. This control has limitations: It can relay to the user only a single piece of information, the text used to represent the car model. Work can be done to display images of the car models in a separate control based on the selection in the list, but this still mandates users to make their selection before seeing exactly what it is they are choosing. In contrast, WPF has the flexibility to display many pieces of information in each combo box item, like a one-stop shop for all the information the user will need to make their decision (see Figure 1-2 for a WPF combo box).

A typical combo box.

Figure 1-1. A typical combo box.

Figure 1-2 shows a sample combo box in WPF. The way the combo box item is rendered is defined using a data template. (I cover Data Templates in Chapter 3 of this minibook.) Each item in this combo box is rendered to provide the user a visual cue along with multiple data fields. Displaying all this information enables users to make an educated decision about the choice they are making.

Visualizing data — a WPF combo box.

Figure 1-2. Visualizing data — a WPF combo box.

Introducing XAML

WPF enables you to build user interfaces declaratively. XAML (hint: it rhymes with camel) forms the foundation of WPF. XAML is similar to HTML in the sense that interface elements are defined using a tag-based syntax.

Note

XAML is XML-based and as such it must be well formed, meaning all opening tags require closing tags, and all elements and attributes contained in the document must validate strictly against the specified schemas.

By default, when creating a WPF application in Visual Studio 2010, the following schemas are represented in generated XAML files:

  • http://schemas.microsoft.com/winfx/2006/xaml/presentation: This schema represents the default Windows Presentation Framework namespace.

  • http://schemas.microsoft.com/winfx/2006/xaml: This schema represents a set of classes that map to CLR objects.

Most CLR objects can be expressed as XAML elements (with the exception of abstract base classes and some other nonabstract base classes used strictly for inheritance purposes in the CLR). XAML elements are mapped to classes; attributes are mapped to properties or events.

At runtime when a XAML element is processed, the default constructor for its underlying class is called, and the object is instantiated; its properties and events are set based on the attribute values specified in XAML.

I'm a firm believer that the best way to become comfortable using WPF and XAML is to jump right in and give it a try. The next section reviews more XAML basics and gets you started on the path of WPF application development.

Diving In! Creating Your First WPF Application

Now it's time to get comfortable, stop for a moment, go grab a caffeinated beverage, sit in a comfortable chair, pull up to your computer, and get ready to go!

To create your first project, follow these steps:

  1. Open Visual Studio 2010.

  2. Create a new project by choosing File

    Diving In! Creating Your First WPF Application
  3. In the Installed Templates region under the "Visual C#" section in the tree, click on the Windows item.

  4. Select WPF Application from the list box of templates located in the center of the window.

  5. In the Name text box, enter MyFirstWPFApplication (this also sets the name of the solution to the same value, which is okay). (See Figure 1-3.)

  6. Click OK.

    Creating a project in the New Project dialog box.

    Figure 1-3. Creating a project in the New Project dialog box.

Visual Studio now does its thing, creating the solution structure of the application. By default, as shown in Figure 1-4, the WPF Application template creates two XAML files along with their respective code-behind files: App.xaml (App.xaml.cs) and MainWindow.xaml (MainWindow.xaml.cs). (See Figure 1-4.)

WPF Application solution structure

Figure 1-4. WPF Application solution structure

App.xaml represents the entry-point of the application. This is where application-wide (globally scoped) resources and the startup window are defined. (See Listing 1-1.)

Note

Resources are a keyed collection of reusable objects. Resources can be created and retrieved using both XAML and C#. Resources can be anything — data templates, arrays of strings, or brushes used to color the background of text boxes. Resources are also scoped, meaning they can be available to the entire Application (global), to the Window, to the User Control, or even to only a specific control.

Example 1-1. App.xaml

<Application x:Class="MyFirstWPFApplication.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>

    </Application.Resources>
</Application>

Listing 1-1 displays the XAML that was generated by the WPF Application template in Visual Studio. Note that the WPF namespaces are defined. The namespace that represents the CLR objects will be distinguished in the XAML file with the .x prefix.

The StartupUri value defines the window that will be displayed after the application is executed. In this case, the MainWindow.xaml window will be displayed.

The x:Class attribute defines the C# code-behind file of this XAML file. If you open App.xaml.cs, you see that its class name is App and it inherits from the Application class (which is the root element of the XAML file).

Note

C# uses namespaces to organize and locate classes. In order to create objects from a specific namespace, you use the "using" syntax at the top of your class definitions. Similar to C#, XAML also requires you to declare which namespaces are used in the document. Namespaces are typically defined as an attribute within the root element of the document, the root element is the first XML tag in the XAML document. XAML uses XML syntax to define a namespace — "xmlns" means "XML namespace," and it's typically followed by a colon (:) and then an alias. This alias is the shorthand reference to the namespace throughout the XAML document; it's what you use to instantiate an object from a class in that namespace.

For instance, if you want to add the namespace MyTemplates.DataTemplates from the assembly MyTemplates.dll, you could define the namespace as:

xmlns:myDTs="clr-namespace:MyTemplates.DataTemplates;assembly=MyTemplates.dll"

You will then be able to instantiate an object from the MyTemplates.DataTemplates namespace as follows:

<myDTs:myClass></myDTs:myClass>

Declaring an application-scoped resource

To demonstrate the creation and use of a global application-scoped resource, in this section we create a resource that holds a string used in our application. An application-scoped resource is available to all Windows and user controls defined in the project. Follow these steps:

  1. Add the System namespace located in the mscorlib.dll assembly.

    This is where the String class is located.

  2. To do this, add the following namespace to the App.xaml root element:

    xmlns:sys="clr-namespace:System;assembly=mscorlib"

    The String class is now available for use throughout the App.xaml document.

  3. Create the resource between the Application.Resource tags, add the following String class element:

    <sys:String x:Key="Purpose">Hello WPF World!</sys:String>

    This element instantiates an object of type String, initialized to the value Hello WPF World!, and keyed off of the key Purpose. This resource is now available throughout the MyFirstWPFApplication application by requesting the resource "Purpose." (See Listing 1-2.)

Example 1-2. Updated App.xaml with Resource and System Namespace Defined

<Application x:Class="MyFirstWPFApplication.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <sys:String x:Key="Purpose">Hello WPF World!</sys:String>
    </Application.Resources>
</Application>

Note

You may observe the Application.Resource tag looks kind of odd. Application.Resources does not define a class as most XAML elements do. It is actually assigning a value to the Resources property of its containing Application object.

This type of tag is called a Property Element, an XML element that represents a property (or attribute) of an object. Property Elements are used when complex objects are assigned to a property of an object that can't be expressed as a simple string value. Property Elements must be contained within the tags of the parent element — in this case, within the Application tags.

Making the application do something

If you run the application as is, not much happens beyond the display of an empty window. The empty window is the one defined in MainWindow.xaml.

Note

App.xaml is the entry point of the WPF application. Within App.xaml, the StartupUri value defines the window displayed on application startup. In this case, the StartupUri value is MainWindow.xaml.

Let's add a label to MainWindow.xaml that displays the purpose of the String we defined in our Resources. Just follow these steps:

  1. Open MainWindow.xaml.

  2. Between the Grid tags, define a grid with a single row and single column by adding the following XAML markup:

    <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>

    Each column and row is defined by the ColumnDefinition and RowDefinition element contained within the Grid.ColumnDefinitions and Grid.RowDefinitions properties, respectively. If you want to add more columns, you simply add another ColumnDefinition element to the Grid.ColumnDefinitions Property Entity. The same goes for adding rows: You add an additional RowDefinition element to the Grid.RowDefinitions Property Entity.

  3. Directly below the Grid.RowDefinitions Property entity, create a label using the following XAML:

    <Label x:Name="lblPurpose" Content="{StaticResource Purpose}"
        FontSize="25" Grid.Row="0" Grid.Column="0" />

    This markup instantiates a WPF Label object accessible to the code-behind file (MainWindow.xaml.cs) using the variable lblPurpose. The Content attribute contains the text that is to be displayed in the label; in this case, we will use the Application Resource that we defined in the preceding section by retrieving it using its key value, which is Purpose. The label text is rendered with a font size of 25 units and is to be located in the grid in the first row and first column.

Note

WOW! That line of XAML really packs quite the punch! Let's review some of what is going on in there:

  • x:Name: This attribute assigns a variable name to the object being created by the XAML tag. This enables you to access the object from the code-behind file. In this case, the variable name of the label object being instantiated is lblPurpose.

  • Content: The value assigned to this attribute can be of any type. By default, you can assign it a string value and it will render as you would think a standard label would render. In the WPF reality, Content can be composed of anything: a string, an image, an instance of a user control, a text box, and so forth. For more info, see Chapter 2 of this minibook.

  • FontSize: The size of the font of the label. It is important to note that the size is not denoted in points; it is expressed in Device Independent Units. WPF gets away from the concepts of pixels and points and moves to a universal sizing strategy. Think of Device Independent Units as more of a ratio than a pixel. For instance, if the containing element of the label were 100 units by 100 units, the label would render as ¼ of that size.

  • Grid.Row: Identifies the grid row in which to render the label. Grid row collections are zero-based, meaning the first row is row 0, the second row is row 1, and so on. You should also note that the Label class does not contain a property named Grid. What you see here is the concept of Attached Properties. Attached Properties are a way to assign the context of a current control relative to the properties of an ancestor control. In this case, we assign the label to appear in the first row (row index 0) of its containing grid. Also observe that the label is located within the Grid tags; this is how the ancestor Grid element is located.

  • Grid.Column: Similar to Grid.Row, this attached property identifies the grid column in which to render the label. Together with Grid.Row, both properties identify the cell where the label is located. In this case, we are assigning the label to render in the first column of its containing grid. Grid column collections are also zero-based.

Go ahead and run your application, you will now see Hello World displayed in the label on your Window. Congratulations, you have just created your first WPF application!

Note

The complete solution is available at www.csharpfordummies.net in the chapter downloads.

Whatever XAML Can Do, C# Can Do Better!

Anything that you can implement using XAML can be implemented in C#. This is not true in reverse; not everything you can do in C# can be done in XAML. C# is the obvious choice for performing business logic tasks with procedural code that can't be expressed in XAML. Let's create an identical WPF application to the one we've just created, this time using C# to implement its functionality. Here's all you have to do:

  1. Create a new project by choosing File

    Whatever XAML Can Do, C# Can Do Better!
  2. Under Visual C#, select Windows.

  3. Select WPF Application.

  4. Name the application MyFirstCodeOnlyWPFApplication.

  5. Click OK.

    Visual Studio creates the Solution and Project structure.

  6. Open App.xaml.cs.

  7. Override the OnStartup method to include the creation of the Purpose application resource by adding the following code to the App class:

    protected override void OnStartup(StartupEventArgs e)
    {
        //create and add the Purpose application resource
       string purpose = "Hello WPF World, in C#";
       this.Resources.Add("Purpose", purpose);
    
       base.OnStartup(e);
    }
  8. Open MainWindow.xaml, and give the Grid element a name by adding the following attribute:

    x:Name="gridLayout"
  9. Open MainWindow.xaml.cs, and in the default constructor, after the InitializeComponents method call, add the following code:

    //define grid column and row
    this.gridLayout.ColumnDefinitions.Add(new ColumnDefinition());
    this.gridLayout.RowDefinitions.Add(new RowDefinition());
    
    //obtain label content from the application resource, Purpose
    string purpose = this.TryFindResource("Purpose") as string;
    Label lblPurpose = new Label();
    lblPurpose.Content = purpose;
    lblPurpose.FontSize = 25;
    
    //add label to the grid
    this.gridLayout.Children.Add(lblPurpose);
    
    //assign attached property values
    Grid.SetColumn(lblPurpose, 0);
    Grid.SetRow(lblPurpose, 0);

Run the application and observe the resulting product is similar to that obtained in the section "Diving In! Creating Your First WPF Application," earlier in this chapter.

Note

The complete solution is available at the www.csharpfordummies.net Web site chapter downloads.

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

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