Condividi tramite


Get Started Using Windows Presentation Foundation

This tutorial provides an introduction to the development of a Windows Presentation Foundation (WPF) application that integrates the core elements of most WPF applications: controls, layout, data binding, and styles.

This topic contains the following sections.

  • Summary
  • Prerequisites
  • Create the Application Code Files
  • Building and Running the Application
  • Add Layout
  • Add Controls
  • Add an Image and Title
  • Add Code to Handle Events
  • Create the UI for ExpenseReportPage
  • Add Code to Style a Control
  • Bind Data to a Control
  • Connect Data to Controls
  • Add Style to Data with Data Templates
  • What's Next
  • Related Topics

Summary

This tutorial guides you through the common steps to building a WPF application using the following steps.

  • Defining Extensible Application Markup Language (XAML) markup to design the appearance of the application's user interface (UI).

  • Writing code to build the application's behavior.

  • Adding controls and layout to compose the application UI.

  • Creating styles to create a consistent appearance throughout an application's UI.

  • Binding the UI to data to both populate the UI from data and keep the data and UI synchronized.

By the end of the tutorial, you will have built a standalone Windows application that allows users to select people to show expense reports for. The application will be composed of several pages that are shown from a browser-style window.

After completing the tutorial, you will understand the basic aspects of WPF application development.

The sample code that is used to build this tutorial is available for both C# and Microsoft Visual Basic .NET, and can be found here.

Prerequisites

To build the application that is developed over the course of this tutorial, you will need to have both the Microsoft .NET Framework version 3.0 and the Windows Software Development Kit (SDK) installed.

The tutorial does not assume a particular development environment and is compatible with the most common, including using either command-line compilation or an Integrated Development Environment (IDE) like Microsoft Visual Studio 2005.

To build from the command prompt, you need to use the specially-configured command shell that is installed with the Windows Software Development Kit (SDK). You can find this in the following location:

Start Menu | All Programs | Microsoft Windows SDK | CMD Shell

Alternatively, you can to open the Windows command prompt using the following steps:

  1. From the Start menu, select Run.

  2. Enter the following:

    C:\WINDOWS\system32\cmd.exe /E:ON /V:ON /T:0E /K "C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\SetEnv.Cmd"

  3. Press OK.

SetEnv.cmd sets up the environment that you need to build WPF applications from the command prompt.

Create the Application Code Files

In this step you set up the infrastructure of your application. It is necessary to create several supporting files in order to successfully compile a project.

  1. Create a new file named HomePage.xaml. This file will be the home page of the application (the first page that is displayed when the application is launched). Its UI will show a list of people who can be selected to show expense reports.

  2. Add a root Page element to HomePage.xaml, with the following configuration:

    • The title bar of the browser is "ExpenseIt".

    • The width of the browser is 550 device-independent pixels.

    • The height of the browser is 350 device-independent pixels.

    • The title of the page is "ExpenseIt - Home".

    Your code should look like this:

    <Page 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="ExpenseIt.HomePage"
      WindowTitle="ExpenseIt"
      Title="ExpenseIt - Home" 
      WindowWidth="550" WindowHeight="350">
    </Page>
    
  3. Create a second file and name it HomePage.xaml.cs. This file will eventually contain code that handles events. For now, it must exist because it's declared in HomePage.xaml using the x:Class attribute**.** The content of HomePage.xaml.cs should look like this:

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Navigation;
    namespace ExpenseIt
    {
        public partial class HomePage : Page
        {
            public HomePage()
            {
                InitializeComponent();
            }
        }
    }
    
  4. Create a third file and name it App.xaml. This file defines a WPF application, and you also use it to specify the UI to automatically show when the application starts; in this case, HomePage.xaml.

    <Application 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      StartupUri="HomePage.xaml">
    </Application>
    
  5. Create a fourth file and name it ExpenseReportPage.xaml. Add a root Page element and "ExpenseIt - View Expense Report" as its page title. This file will have a UI that shows an expense report for the person that is selected on the home page (HomePage.xaml)

    <Page 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="ExpenseIt.ExpenseReportPage"
      Title="ExpenseIt - View Expense Report">
    </Page>
    
  6. Create a fifth file and name it ExpenseReportPage.xaml.cs. This file will eventually be used to bind expense report data to the UI which is defined in ExpenseReportPage.xaml. For now, it must exist because it's declared in ExpenseReportPage.xaml using the x:Class attribute**.** The content of ExpenseReportPage.xaml.cs should look like this:

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Navigation;
    namespace ExpenseIt
    {
        public partial class ExpenseReportPage : Page
        {
            public ExpenseReportPage()
            {
                InitializeComponent();
            }
        }
    }
    
  7. Add an image called watermark.png to the same folder as the five code files that you created in the preceding steps. You can either create your own image, or copy the file of the same name from the sample code.

  8. Create a final file and name it ExpenseIt.csproj. This file is the XML build configuration file for the application, which defines the following:

    • The global build variables for the compiled project.

    • References to the code files.

    • References to the Microsoft .NET Framework version 3.0 assemblies that contain the types that the application uses.

    The content of the build file should look like this:

    <?xml version="1.0" encoding="utf-8"?>
    <Project xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
        <PropertyGroup>
            <AssemblyName>ExpenseIt</AssemblyName>
            <TargetType>winexe</TargetType>
            <OutputPath>bin\$(Configuration)\</OutputPath>
        </PropertyGroup>
        <ItemGroup>
            <Reference Include="System"/>
            <Reference Include="System.Xml"/>
            <Reference Include="System.Data"/>
            <Reference Include="WindowsBase"/>
            <Reference Include="PresentationCore"/>
            <Reference Include="PresentationFramework"/>
        </ItemGroup>
        <ItemGroup>
            <ApplicationDefinition Include="App.xaml"/>
            <Page Include="HomePage.xaml"/>
            <Compile Include="HomePage.xaml.cs" />
            <Page Include="ExpenseReportPage.xaml"/>
            <Compile Include="ExpenseReportPage.xaml.cs" />
            <Resource Include="watermark.png"/>
        </ItemGroup>
        <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets"/>
        <Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets"/>
    </Project>
    

Building and Running the Application

In this step, you use MSBuild to build the application from the project file and application code files that you created in the previous steps.

Open a command shell to the same folder as your project file and application code files.

  1. From the command prompt, run the following command:

    MSBuild ExpenseIt.csproj

    For Microsoft Visual Basic .NET, run the following command instead:

    MSBuild ExpenseIt.vbproj

    To compile and run the application using Visual Studio, open the project file in Visual Studio and press F5.

NoteNote:

Visual Studio 2005 generates a project file automatically. Because this tutorial does not assume that Visual Studio is installed, the process for creating a project file is detailed. For more information on the creation of .csproj files, see Building a Windows Presentation Foundation Application. If you are using Visual Studio to complete this tutorial, overwrite the content of the generated .csproj file with the preceding MSBuild text.

  1. Open the folder that contains the built application executable: expenseit.exe. If built from the command prompt, expenseit.exe is located in the following folder:

    <Folder Containing Application Code Files>\bin\

    If built using Visual Studio, expenseit.exe is located in the following folder instead:

    <Folder Containing Application Code Files>\bin\debug\

  2. From the command prompt, run expenseit.exe. The following figure shows the running application.

ExpenseIt sample screen shot

Add Layout

In this step, you add layout to your application. Layout is the framework within which your actual UI elements will reside, and manages both the size and position of those elements. You add layout to your UI through the use of one of the following layout elements:

Each of these controls supports a type of layout for its child elements. Because the ExpenseIt application UI is composed of pages that can be resized, and each page has controls that will be arranged both horizontally and vertically alongside other controls, a Grid is the ideal layout element for the application.

NoteNote:

For more information on Panel elements, see Panels Overview.

The following XAML adds a Grid to HomePage.xaml:

  1. Open HomePage.xaml

  2. Add the following XAML between the Page tags.

    <Page 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="ExpenseIt.HomePage"
      WindowTitle="ExpenseIt"
      Title="ExpenseIt - Home" 
      WindowWidth="550" WindowHeight="350">
        <Grid Margin="10">
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
            <RowDefinition Height="Auto" />
          </Grid.RowDefinitions>
        </Grid>
    </Page>
    

This XAML defines a grid with a 10 pixel margin that has a single column with three rows. The following step adds controls to each of the cells of the grid.

Add Controls

In this step, you add a TextBlock element, a ListBox, and a Button to the application.

  1. Open HomePage.xaml

  2. Replace the contents of HomePage.xaml with the following XAML.

    <Page 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="ExpenseIt.HomePage"
      WindowTitle="ExpenseIt"
      Title="ExpenseIt - Home" 
      WindowWidth="550" WindowHeight="350">
    
      <Grid Margin="10">
    
        <Grid.ColumnDefinitions>
          <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition />
          <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
    
        <!-- People list-->
        <Border Grid.Column="0" Grid.Row="0" Height="30" Padding="5" Background="#4E87D4">
          <TextBlock VerticalAlignment="Center" Foreground="White">Names</TextBlock>
        </Border>
        <ListBox Name="peopleListBox" Grid.Column="0" Grid.Row="1">
          <ListBoxItem>Mike</ListBoxItem>
          <ListBoxItem>Lisa</ListBoxItem>
          <ListBoxItem>John</ListBoxItem>
          <ListBoxItem>Mary</ListBoxItem>
        </ListBox>
    
        <!-- View report button -->
        <Button Grid.Column="0" Grid.Row="2" Margin="0,10,0,0" Width="125" Height="25" HorizontalAlignment="Right">View</Button>
    
      </Grid>
    
    </Page>
    

    This XAML creates a list of names that a user can select from, as well as a Button to view the expense report for the selected name. The event handler for the Button element is added later in the tutorial.

  3. Compile and run the application.

The following image shows the controls that are created by the code in this step.

ExpenseIt sample screen shot

Add an Image and Title

  1. Open HomePage.xaml.

  2. Replace the contents of HomePage.xaml with the following XAML.

    <Page 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="ExpenseIt.HomePage"
      WindowTitle="ExpenseIt"
      Title="ExpenseIt - Home" 
      WindowWidth="550" WindowHeight="350">
    
      <Grid>
    
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="230" />
          <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition />
        </Grid.RowDefinitions>
    
        <DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
          <Canvas DockPanel.Dock="Left" Width="230" Height="100">
            <Image Source="watermark.png" />
          </Canvas>
          <TextBlock VerticalAlignment="Center" FontFamily="Trebuchet MS" FontWeight="Bold" FontSize="18" Foreground="#0066cc">View Expense Report</TextBlock>
        </DockPanel>
    
        <Grid Margin="10" Grid.Column="1" Grid.Row="1">
    
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
            <RowDefinition Height="Auto" />
          </Grid.RowDefinitions>
    
          <!-- People list-->
          <Border Grid.Column="0" Grid.Row="0" Height="30" Padding="5" Background="#4E87D4">
            <TextBlock VerticalAlignment="Center" Foreground="White">Names</TextBlock>
          </Border>
          <ListBox Name="peopleListBox" Grid.Column="0" Grid.Row="1">
            <ListBoxItem>Mike</ListBoxItem>
            <ListBoxItem>Lisa</ListBoxItem>
            <ListBoxItem>John</ListBoxItem>
            <ListBoxItem>Mary</ListBoxItem>
          </ListBox>
    
          <!-- View report button -->
          <Button Grid.Column="0" Grid.Row="2" Margin="0,10,0,0" Width="125" Height="25" HorizontalAlignment="Right">View</Button>
    
        </Grid>
    
      </Grid>
    </Page>
    

    This XAML updates the Grid by:

    • Creating a new grid with two rows.

    • Adding a DockPanel with a Canvas, Image, and TextBlock to the first row. The DockPanel spans the two columns of the first row which, in conjunction with the Canvas being docked to the left, enables the TextBlock to overlap the Image.

    • Using the Source attribute of the Image element to specify the source image: watermark.png.

    • Adding the following title text to the TextBlock: "View Expense Report".

    • Using the attributes of the Canvas and TextBlock to configure their appearance and size.

    • Moving the grid that HomePage.xaml originally contained to the second column of the second row of the new grid.

  3. Compile and run the application.

The following figure shows the results of this step.

ExpenseIt sample screen shot

Add Code to Handle Events

  1. Open HomePage.xaml.

  2. Replace the Button element defined in the previous step with the following code.

    ...
    <Button Grid.Column="0" Grid.Row="2" Width="125" Height="25" Margin="0,10,0,0" HorizontalAlignment="Right" Click="viewButton_Click">View</Button>
    ...
    
    NoteNote:

    The name of the Button event to handle is Click. The name of the developer-defined event handler is viewButton_Click. The event handler is registered with the Click event for the Button control.

  3. Open the HomePage.xaml.cs that you created in the Set up the Structure of the Application step of the tutorial.

  4. Overwrite the contents of the file with the following code. This adds code to handle the Click event, which causes the ExpenseReportPage.xaml file to be navigated to.

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Navigation;
    namespace ExpenseIt
    {
        public partial class HomePage : Page
        {
            public HomePage()
            {
                InitializeComponent();
            }
            private void viewButton_Click(object sender, RoutedEventArgs args)
            {
                // View Expense Report
                ExpenseReportPage expenseReportPage = new ExpenseReportPage();
                this.NavigationService.Navigate(expenseReportPage);
            }
        }
    }
    

Create the UI for ExpenseReportPage

HomePage.xaml and ExpenseReportPage.xaml are similar. HomePage.xaml displays a list of employees, and ExpenseReportPage.xaml displays expenses for each employee.

  1. Open the ExpenseReportPage.xaml file and add the following code.

    <Page 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="ExpenseIt.ExpenseReportPage"
      Title="ExpenseIt - View Expense Report">
    
      <Grid>
    
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="230" />
          <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition />
        </Grid.RowDefinitions>
    
        <DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
          <Canvas DockPanel.Dock="Left" Width="230" Height="100">
            <Image Source="watermark.png" />
          </Canvas>
          <TextBlock VerticalAlignment="Center" FontFamily="Trebuchet MS" FontWeight="Bold" FontSize="18" Foreground="#0066cc">Expense Report For:</TextBlock>
        </DockPanel>
    
        <Grid Margin="10" Grid.Column="1" Grid.Row="1">
    
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition />
          </Grid.RowDefinitions>
    
          <!-- Name -->
          <TextBlock Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Margin="0,0,0,10">
            <TextBlock FontWeight="Bold">Name:</TextBlock>
            <TextBlock></TextBlock>
          </TextBlock>
    
          <!-- Department -->
          <TextBlock Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Margin="0,0,0,10">
            <TextBlock FontWeight="Bold">Department:</TextBlock>
            <TextBlock></TextBlock>
          </TextBlock>
    
          <Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="3">
    
            <Grid.ColumnDefinitions>
              <ColumnDefinition />
              <ColumnDefinition Width="10" />
              <ColumnDefinition />
            </Grid.ColumnDefinitions>
    
            <Grid.RowDefinitions>
              <RowDefinition Height="Auto" />
              <RowDefinition />
            </Grid.RowDefinitions>
    
            <!-- Expense type list-->
            <Border Grid.Column="0" Grid.Row="0" Height="30" Padding="5" Background="#4E87D4">
              <TextBlock VerticalAlignment="Center" Foreground="White">Expense Type</TextBlock>
            </Border>
            <ListBox Grid.Column="0" Grid.Row="1" />
    
            <!-- Amount list -->
            <Border Grid.Column="2" Grid.Row="0" Height="30" Padding="5" Background="#4E87D4">
              <TextBlock VerticalAlignment="Center" Foreground="White">Amount</TextBlock>
            </Border>
            <ListBox Grid.Column="2" Grid.Row="1" />
    
          </Grid>
        </Grid>
      </Grid>
    </Page>
    

    This code adds controls and layout that create the basic UI structure for ExpenseReportPage.xaml, just as you did for HomePage.xaml in the first step. It also adds the background and fill colors of the various UI elements.

  2. Compile and run the application.

The following image shows the UI elements added to ExpenseReportPage.xaml.

ExpenseIt sample screen shot

Add Code to Style a Control

  1. Open the App.xaml file that you created in the Set up the Structure of the Application step of this tutorial.

  2. Overwrite the content of the file with the following code:

    <Application 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      StartupUri="HomePage.xaml">
    
      <Application.Resources>
    
        <!-- Background image style -->
        <Style x:Key="backgroundImageStyle">
          <Setter Property="Image.Source" Value="watermark.png"/>
        </Style>
    
        <!-- Header text style -->
        <Style x:Key="headerTextStyle">
          <Setter Property="TextBlock.VerticalAlignment" Value="Center"></Setter>
          <Setter Property="TextBlock.FontFamily" Value="Trebuchet MS"></Setter>
          <Setter Property="TextBlock.FontWeight" Value="Bold"></Setter>
          <Setter Property="TextBlock.FontSize" Value="18"></Setter>
          <Setter Property="TextBlock.Foreground" Value="#0066cc"></Setter>
        </Style>
    
        <!-- Label style-->
        <Style x:Key="labelStyle" TargetType="{x:Type TextBlock}">
          <Setter Property="VerticalAlignment" Value="Top" />
          <Setter Property="HorizontalAlignment" Value="Left" />
          <Setter Property="FontWeight" Value="Bold" />
          <Setter Property="Margin" Value="0,0,0,5" />
        </Style>
    
        <!-- List header style-->
        <Style x:Key="listHeaderStyle" TargetType="{x:Type Border}">
          <Setter Property="Height" Value="30" />
          <Setter Property="Padding" Value="5" />
          <Setter Property="Background" Value="#4E87D4" />
        </Style>
    
        <!-- List header text style-->
        <Style x:Key="listHeaderTextStyle" TargetType="{x:Type TextBlock}">
          <Setter Property="Foreground" Value="White" />
          <Setter Property="VerticalAlignment" Value="Center" />
          <Setter Property="HorizontalAlignment" Value="Left" />
        </Style>
    
        <!-- Button style-->
        <Style x:Key="buttonStyle" TargetType="{x:Type Button}">
          <Setter Property="Width" Value="125" />
          <Setter Property="Height" Value="25" />
          <Setter Property="Margin" Value="0,10,0,0" />
          <Setter Property="HorizontalAlignment" Value="Right" />
        </Style>
    
      </Application.Resources>
    
    </Application>
    

    This XAML adds the following styles:

    • headerTextStyle: To format the page title TextBlock.

    • labelStyle: To format the TextBlock labels.

    • listHeaderStyle: To format the list header Border controls.

    • listHeaderTextStyle: To format the list header TextBlock.

    • buttonStyle: To format the button on HomePage.xaml.

    Notice that the styles are resources scoped to the entire Application, by being made children of the Application.Resources property element. For an example of using resources in a .NET Framework 3.0 application, see How to: Use Application Resources.

  3. Open HomePage.xaml.

  4. Overwrite the content of the file with the following code. Notice that you are removing attributes from the elements and replacing them with styles.

    <Page 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="ExpenseIt.HomePage"
      WindowTitle="ExpenseIt"
      Title="ExpenseIt - Home" 
      WindowWidth="550" WindowHeight="350">
    
      <Grid>
    
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="230" />
          <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition />
        </Grid.RowDefinitions>
    
        <DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
          <Canvas DockPanel.Dock="Left" Width="230" Height="100">
            <Image Style="{StaticResource backgroundImageStyle}" />
          </Canvas>
          <TextBlock Style="{StaticResource headerTextStyle}">View Expense Report</TextBlock>
        </DockPanel>
    
        <Grid Margin="10" Grid.Column="1" Grid.Row="1">
    
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
            <RowDefinition Height="Auto" />
          </Grid.RowDefinitions>
    
          <!-- People list-->
          <Border Grid.Column="0" Grid.Row="0" Style="{StaticResource listHeaderStyle}">
            <TextBlock Style="{StaticResource listHeaderTextStyle}">Names</TextBlock>
          </Border>
          <ListBox Name="peopleListBox" Grid.Column="0" Grid.Row="1">
            <ListBoxItem>Mike</ListBoxItem>
            <ListBoxItem>Lisa</ListBoxItem>
            <ListBoxItem>John</ListBoxItem>
            <ListBoxItem>Mary</ListBoxItem>
          </ListBox>
    
          <!-- View report button -->
          <Button Grid.Column="0" Grid.Row="2" Style="{StaticResource buttonStyle}" Click="viewButton_Click">View</Button>
    
        </Grid>
    
      </Grid>
    
    </Page>
    
  5. Open ExpenseReportPage.xaml.

  6. Overwrite the content of the file with the following code.

    <Page 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="ExpenseIt.ExpenseReportPage"
      Title="ExpenseIt - View Expense Report">
    
      <Grid>
    
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="230" />
          <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition />
        </Grid.RowDefinitions>
    
        <DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
          <Canvas DockPanel.Dock="Left" Width="230" Height="100">
            <Image Style="{StaticResource backgroundImageStyle}" />
          </Canvas>
          <TextBlock Style="{StaticResource headerTextStyle}">Expense Report For:</TextBlock>
        </DockPanel>
    
        <Grid Margin="10" Grid.Column="1" Grid.Row="1">
    
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition />
          </Grid.RowDefinitions>
    
          <!-- Name -->
          <TextBlock Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Style="{StaticResource labelStyle}">
            <TextBlock FontWeight="Bold">Name:</TextBlock>
            <TextBlock></TextBlock>
          </TextBlock>
    
          <!-- Department -->
          <TextBlock Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Style="{StaticResource labelStyle}">
            <TextBlock FontWeight="Bold">Department:</TextBlock>
            <TextBlock></TextBlock>
          </TextBlock>
    
          <Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="3">
    
            <Grid.ColumnDefinitions>
              <ColumnDefinition />
              <ColumnDefinition Width="10" />
              <ColumnDefinition />
            </Grid.ColumnDefinitions>
    
            <Grid.RowDefinitions>
              <RowDefinition Height="Auto" />
              <RowDefinition />
            </Grid.RowDefinitions>
    
            <!-- Expense type list-->
            <Border Grid.Column="0" Grid.Row="0" Style="{StaticResource listHeaderStyle}">
              <TextBlock Style="{StaticResource listHeaderTextStyle}">Expense Type</TextBlock>
            </Border>
            <ListBox Grid.Column="0" Grid.Row="1" />
    
            <!-- Amount list -->
            <Border Grid.Column="2" Grid.Row="0" Style="{StaticResource listHeaderStyle}">
              <TextBlock Style="{StaticResource listHeaderTextStyle}">Amount</TextBlock>
            </Border>
            <ListBox Grid.Column="2" Grid.Row="1" />
    
          </Grid>
    
        </Grid>
    
      </Grid>
    
    </Page>
    

    This code replaces the original element attributes with the newly created styles.

  7. Compile and run the application. After adding the code in this step, the application looks the same as it did previously. The difference is that the UI elements are created with styles rather than attributes declared on elements. This approach is more flexible and requires less code.

Bind Data to a Control

  1. Open HomePage.xaml.

  2. Overwrite the content of the file with the following code.

    <Page 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="ExpenseIt.HomePage"
      WindowTitle="ExpenseIt"
      Title="ExpenseIt - Home" 
      WindowWidth="550" WindowHeight="350">
    
      <Grid>
    
        <Grid.Resources>
    
          <!-- Expense Report Data -->
          <XmlDataProvider x:Key="ExpenseDataSource" XPath="Expenses">
            <x:XData>
              <Expenses >
                <Person Name="Mike" Department="Legal">
                  <Expense ExpenseType="Lunch" ExpenseAmount="50" />
                  <Expense ExpenseType="Transportation" ExpenseAmount="50" />
                </Person>
                <Person Name="Lisa" Department="Marketing">
                  <Expense ExpenseType="Document printing"
                      ExpenseAmount="50"/>
                  <Expense ExpenseType="Gift" ExpenseAmount="125" />
                </Person>
                <Person Name="John" Department="Engineering">
                  <Expense ExpenseType="Magazine subscription" 
                     ExpenseAmount="50"/>
                  <Expense ExpenseType="New machine" ExpenseAmount="600" />
                  <Expense ExpenseType="Software" ExpenseAmount="500" />
                </Person>
                <Person Name="Mary" Department="Finance">
                  <Expense ExpenseType="Dinner" ExpenseAmount="100" />
                </Person>
              </Expenses>
            </x:XData>
          </XmlDataProvider>
    
          <!-- Name item template -->
          <DataTemplate x:Key="nameItemTemplate">
            <TextBlock Text="{Binding XPath=@Name}"/>
          </DataTemplate>
    
        </Grid.Resources>
    
    
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="230" />
          <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition />
        </Grid.RowDefinitions>
    
        <DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
          <Canvas DockPanel.Dock="Left" Width="230" Height="100">
            <Image Style="{StaticResource backgroundImageStyle}" />
          </Canvas>
          <TextBlock Style="{StaticResource headerTextStyle}">Expense Report For:</TextBlock>
        </DockPanel>
    
        <Grid Margin="10" Grid.Column="1" Grid.Row="1">
    
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
            <RowDefinition Height="Auto" />
          </Grid.RowDefinitions>
    
          <!-- People list-->
          <Border Grid.Column="0" Grid.Row="0" Style="{StaticResource listHeaderStyle}">
            <TextBlock Style="{StaticResource listHeaderTextStyle}">Names</TextBlock>
          </Border>
          <ListBox Name="peopleListBox" Grid.Column="0" Grid.Row="1" 
            ItemsSource="{Binding Source={StaticResource ExpenseDataSource}, XPath=Person}" 
            ItemTemplate="{StaticResource nameItemTemplate}" />
    
          <!-- View report button -->
          <Button Grid.Column="0" Grid.Row="2" Style="{StaticResource buttonStyle}" Click="viewButton_Click">View</Button>
    
        </Grid>
    
      </Grid>
    
    </Page>
    

    This code creates the XML data that is bound to various controls. Notice that the data is supplied within a Grid resource.

Connect Data to Controls

  1. Open HomePage.xaml.cs.

  2. Overwrite the content of the file with the following code.

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Navigation;
    namespace ExpenseIt
    {
        public partial class HomePage : Page
        {
            public HomePage()
            {
                InitializeComponent();
            }
    
            private void viewButton_Click(object sender, RoutedEventArgs args)
            {
                // Create a new expense report page and pass it the selected person
                // by using the non-default constructor.
                ExpenseReportPage expenseReportPage = new ExpenseReportPage(this.peopleListBox.SelectedItem);
    
                // Navigate to the expense report page
                this.NavigationService.Navigate(expenseReportPage);
            }
        }
    }
    
  3. Open ExpenseReportPage.xaml.cs.

  4. Overwrite the content of the file with the following code.

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Navigation;
    namespace ExpenseIt
    {
        public partial class ExpenseReportPage : Page
        {
            public ExpenseReportPage(object data)
            {
                InitializeComponent();
    
                // Bind to expense report data
                this.DataContext = data;
            }
        }
    }
    

    This code retrieves the current item that is selected in the list of people on HomePage, and passes its reference to the constructor of ExpenseReportPage during insantiation. ExpenseReportPage sets its data context with the passed item, which is what the controls defined in ExpenseReportPage.xaml will bind to.

Add Style to Data with Data Templates

  1. Open ExpenseReportPage.xaml.

  2. Overwrite the content of the file with the following code.

    <Page 
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="ExpenseIt.ExpenseReportPage"
      Title="ExpenseIt - View Expense Report">
    
      <Grid>
    
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="230" />
          <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition />
        </Grid.RowDefinitions>
    
        <DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
          <Canvas DockPanel.Dock="Left" Width="230" Height="100">
            <Image Style="{StaticResource backgroundImageStyle}" />
          </Canvas>
          <TextBlock Style="{StaticResource headerTextStyle}">Expense Report For:</TextBlock>
        </DockPanel>
    
        <Grid Margin="10" Grid.Column="1" Grid.Row="1">
    
          <Grid.Resources>
            <!-- Reason item template -->
            <DataTemplate x:Key="typeItemTemplate">
              <TextBlock Text="{Binding XPath=@ExpenseType}"/>
            </DataTemplate>
            <!-- Amount item template -->
            <DataTemplate x:Key="amountItemTemplate">
              <TextBlock Text="{Binding XPath=@ExpenseAmount}"/>
            </DataTemplate>
          </Grid.Resources>
    
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition />
          </Grid.RowDefinitions>
    
          <!-- Name -->
          <TextBlock Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Style="{StaticResource labelStyle}">
            <TextBlock FontWeight="Bold">Name:</TextBlock>
            <TextBlock Text="{Binding XPath=@Name}" />
          </TextBlock>
    
          <!-- Department -->
          <TextBlock Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Style="{StaticResource labelStyle}">
            <TextBlock FontWeight="Bold">Department:</TextBlock>
            <TextBlock Text="{Binding XPath=@Department}" />
          </TextBlock>
    
          <Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="3">
    
            <Grid.ColumnDefinitions>
              <ColumnDefinition />
              <ColumnDefinition Width="10" />
              <ColumnDefinition />
            </Grid.ColumnDefinitions>
    
            <Grid.RowDefinitions>
              <RowDefinition Height="Auto" />
              <RowDefinition />
            </Grid.RowDefinitions>
    
            <!-- Expense type list-->
            <Border Grid.Column="0" Grid.Row="0" Style="{StaticResource listHeaderStyle}">
              <TextBlock Style="{StaticResource listHeaderTextStyle}">Expense Type</TextBlock>
            </Border>
            <ListBox Grid.Column="0" Grid.Row="1" ItemsSource="{Binding XPath=Expense}" ItemTemplate="{StaticResource typeItemTemplate}" />
    
            <!-- Amount list -->
            <Border Grid.Column="2" Grid.Row="0" Style="{StaticResource listHeaderStyle}">
              <TextBlock Style="{StaticResource listHeaderTextStyle}">Amount</TextBlock>
            </Border>
            <ListBox Grid.Column="2" Grid.Row="1" ItemsSource="{Binding XPath=Expense}" ItemTemplate="{StaticResource amountItemTemplate}" />
    
          </Grid>
    
        </Grid>
    
      </Grid>
    
    </Page>
    

    This code creates styles for the data using data templates. Notice that the data templates are defined as Grid resources.

  3. Compile and run the application.

The following two figures show both pages of the ExpenseIt application with controls, layout, styles, data binding and data templates applied:

ExpenseIt sample screen shots

What's Next

You now have a number of techniques at your disposal for creating a UI using Windows Presentation Foundation (WPF). You should now have a broad understanding of the basic building blocks of a data-bound .NET Framework 3.0 application. This topic is by no means exhaustive, but hopefully you also now have a sense of some of the possibilities you might discover on your own beyond the techniques in this topic.

Panels are explored in greater detail in the Panels Overview. Data templating is explored in greater depth in the Data Templating Overview.

See Also

Concepts

The Layout System
Panels Overview
Data Binding Overview
Data Templating Overview
Building a Windows Presentation Foundation Application