Windows Presentation Foundation

Hello, WPF

WPF from Scratch
Navigation Applications
Content Model
Layout
Controls
Data Binding
Dependency Properties
Resources
Styles and Control Templates
Graphics
Application Deployment
Where Are We?

Layout

Introduction
Layout Basics
DockPanel
StackPanel
Grid
Canvas
Viewbox
Text Layout
Common Layout Properties
When Content Doesn't Fit
Custom Layout
Where Are We?

Controls

Introduction
What Are Controls?
Handling Input
Built-In Controls
Where Are We?

Data Binding

Introduction
Without Data Binding
Data Binding
Binding to List Data
Data Sources
Master-Detail Binding
Where Are We?

Styles and Control Templates

Introduction
Without Styles
Inline Styles
Named Styles
Element-Typed Styles
Data Templates and Styles
Triggers
Control Templates
Where Are We?

Resources

Introduction
Creating and Using Resources
Resources and Styles
Binary Resources
Global Applications
Where Are We?

Graphics

Introduction
Graphics Fundamentals
Shapes
Brushes and Pens
Transformations
Visual-Layer Programming
Video and 3-D
Where Are We?

Animation

Animation Fundamentals
Timelines
Storyboards
Key Frame Animations
Creating Animations Procedurally
Where Are We?

Custom Controls

Introduction
Custom Control Basics
Choosing a Base Class
Custom Functionality
Templates
Default Visuals
Where Are We?

ClickOnce Deployment

A Brief History of Windows Deployment
ClickOnce: Local Install
The Pieces of ClickOnce
Publish Properties
Deploying Updates
ClickOnce: Express Applications
Choosing Local Install versus Express
Signing ClickOnce Applications
Programming for ClickOnce
Security Considerations
Where Are We?

WPF from Scratch


WPF from Scratch

Example 1-1 is pretty much the smallest WPF application you can write in C#.

Example 1-1. Minimal C# WPF application
// MyApp.cs
using System;
using System.Windows; // the root WPF namespace

namespace MyFirstAvalonApp {
  class MyApp {
    [STAThread]
    static void Main(  ) {
      // the WPF message box
      MessageBox.Show("Hello, Avalon");
    }
  }
}


If you're not familiar with the STAThread attribute, it's a signal to .NET that when COM is initialized on the application's main thread, to make sure it's initialized to be compatible with single-threaded UI work , as required by WPF applications.


1.1.1. Building Applications

Building this application is a matter of firing off the C# compiler from a command shell with the appropriate environment variables,[*] as in Example 1-2.

[*] Start Programs Microsoft WinFX SDK Debug Build Environment or Release Build Environment.

Example 1-2. Building a WPF application manually
C:\1st>csc /target:winexe /out:.\1st.exe
  /r:System.dll
  /r:c:\WINDOWS\Microsoft.NET\Windows\v6.0.4030\WindowsBase 
.dll
  /r:c:\WINDOWS\Microsoft.NET\Windows\v6.0.4030\PresentationCore 
.dll
  /r:c:\WINDOWS\Microsoft.NET\Windows\v6.0.4030\PresentationFramework 
.dll
  MyApp.cs

Microsoft (R) Visual C# 2005 Compiler version 8.00.50215.44
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50215
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.

Here, we're telling the C# compiler that we'd like to create a Windows application (instead of a Console application, which we get by default), putting the result, 1st.exe, into the current folder, bringing in the three main WPF assemblies (WindowsBase, PresentationCore and PresentationFramework), along with the core .NET System assembly, and compiling the MyApp.cs source file.

Running the resulting 1st.exe produces the world's lamest WPF application, as shown in Figure 1-1.

Figure 1-1. A lame WPF application


In anticipation of less lame WPF applications, refactoring the compilation command line into an msbuild project file is recommended, as in Example 1-3.

Example 1-3. A minimal msbuild project file

<!-- 1st.csproj -->
<Project
  DefaultTargets="Build"
  xmlns="http://schemas.microsoft.com/developer/msbuild 
/2003">
  <PropertyGroup>
    <OutputType>winexe</OutputType>
    <OutputPath>.\</OutputPath>

    <Assembly>1st.exe</Assembly>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="MyApp.cs" />
    <Reference Include="System" />

    <Reference Include="WindowsBase" />
    <Reference Include="PresentationCore" />
    <Reference Include="PresentationFramework" />
  </ItemGroup>
  <Import Project="$(MsbuildBinPath)\Microsoft.CSharp.targets" />
</Project>


Msbuild is a .NET 2.0 command-line tool that understands XML files in the form shown in Example 1-3. The file format is shared between msbuild and Visual Studio 2005 so that you can use the same project files for both command-line and IDE builds. In this .csproj file (which stands for "C# Project"), we're saying the same things that we said to the C# compileri.e., that we'd like a Windows application, that we'd like the output to be 1st.exe in the current folder, and that we'd like to reference the main WPF assemblies while compiling the MyApp.cs file. The actual smarts of how to turn these minimal settings into a compiled WPF application are contained in the .NET 2.0 Microsoft.CSharp.targets file that imported at the bottom of the file.

Executing msbuild.exe on the 1st.csproj file looks like Example 1-4.

Example 1-4. Building using msbuild
C:\1st>msbuild 1st.csproj

Microsoft (R) Build Engine Version 2.0.50215.44
[Microsoft .NET Framework, Version 2.0.50215.44]
Copyright (C) Microsoft Corporation 2005. All rights reserved.

Build started 7/6/2005 8:20:39 PM.
________________________________________________  _  _
Project "C:\1st\1st.csproj" (default targets):

Target PrepareForBuild:
    Creating directory "obj\Release\".
Target CompileRdlFiles:
    Skipping target "CompileRdlFiles" because it has no inputs.
Target CoreCompile:
    Csc.exe /noconfig /nowarn:"1701;1702" /reference:C:\WINDOWS\Microsoft.net\Wi
ndows\v6.0.4030\PresentationCore.dll /reference:C:\WINDOWS\Microsoft.net\Windows
\v6.0.4030\PresentationFramework.dll /reference:C:\WINDOWS\Microsoft.NET\Framewo
rk\v2.0.50215\System.dll /reference:C:\WINDOWS\Microsoft.net\Windows\v6.0.4030\W
indowsBase.dll /out:obj\Release\1st.exe /target:winexe MyApp.cs
Target CopyAppConfigFile:
    Skipping target "CopyAppConfigFile" because it has no outputs.
Target CopyFilesToOutputDirectory:
    Copying file from "obj\Release\1st.exe" to ".\1st.exe".
    1st -> C:\1st\1st.exe

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.98

As I mentioned, msbuild and Visual Studio 2005 share a project file format, so loading the project file into VS is as easy as double-clicking on 1st.csproj, which provides us all of the rights and privileges thereof (as shown in Figure 1-2).

Figure 1-2. Loading the minimal msbuild project file into Visual Studio


Unfortunately, as nice as the project file makes building our WPF application, the application itself is still lame.

1.1.2. The Application Object

A real WPF application is going to need more than a message box. WPF applications have an instance of the Application class from the System.Windows namespace. The Application class provides events like StartingUp and ShuttingDown for tracking lifetime; methods like Run for starting the application; and properties like Current, ShutdownMode, and MainWindow for finding the global application object, choosing when it shuts down, and getting the application's main window. Typically, the Application class serves as a base for custom application-wide behavior, as in Example 1-5.

Example 1-5. A less minimal WPF application
// MyApp.cs
using System;
using System.Windows;

namespace MyFirstAvalonApp {
  class MyApp : Application {
    [STAThread]
    static void Main(string[] args) {
      MyApp app = new MyApp(  );
      app.StartingUp += app.AppStartingUp;
      app.Run(args);
    }

    void AppStartingUp(object sender, StartingUpCancelEventArgs 
 e) {
      // By default, when all top level windows
      // are closed, the app shuts down
      Window window = new Window(  );
      window.Text = "Hello, Avalon";
      window.Show(  );
    }
  }
}


Here, our MyApp class derives from the Application base class. In Main, we create an instance of the MyApp class, add a handler to the StartingUp event, and kick things off with a call to the Run method, passing the command-line arguments passed to Main. Those same command-line arguments are available in the StartingUpCancelEventArgs passed to the StartingUp event handler. (The StartingUp event handler will show its value as we move responsibility for the application's entry point to WPF later in this chapter.)

Our StartingUp handler creates our sample's top-level window, which is an instance of the built-in WPF Window class, making our sample WPF application more interesting from a developer point of view, although visually less so, as shown in Figure 1-3.

Figure 1-3. A less lame WPF application


While we can create instances of the built-in classes of WPF like Window, populating them and wiring them up from the application, it's much more encapsulating (not to mention abstracting) to create custom classes for such things, like the Window1 class in Example 1-6.

Example 1-6. Window class declaring its own controls
// Window1.cs
using System;
using System.Windows;
using System.Windows.Controls; // Button et al

namespace MyFirstAvalonApp {
  class Window1 : Window {
    public Window1(  ) {
      this.Text = "Hello, Avalon";

      // Do something interesting (sorta...)
      Button button = new Button(  );
      button.Content = "Click me, baby, one more time!";
      button.Width = 200;
      button.Height = 25;
      button.Click += button_Click;

      this.AddChild(button);
    }

    void button_Click(object sender, RoutedEventArgs e) {
      MessageBox.Show(
        "You've done that before, haven't you...",
        "Nice!");
    }
  }
}

In addition to setting its caption text, an instance of our Window1 class will include a button with its Content, Width, and Height properties set and its Click event handled. With this initialization handled in the Window1 class itself, our app's startup code looks a bit simpler (even though the application itself has gotten "richer"), as in Example 1-7.

Example 1-7. Simplified Application instance
// MyApp.cs
using System;
using System.Windows;

namespace MyFirstAvalonApp {
  class MyApp : Application {
    [STAThread]
    static void Main(string[] args) {
      MyApp app = new MyApp(  );
      app.StartingUp += app.AppStartingUp;
      app.Run(args);
    }

    void AppStartingUp(object sender, StartingUpCancelEventArgs e) {
      // Let the Window1 initialize itself
      Window window = new Window1(  );
      window.Show(  );
    }
  }
}

The results, shown in Figure 1-4, are unlikely to surprise you much.

Figure 1-4. A slightly more interesting WPF application


As the Window1 class gets more interesting, we're mixing two very separate kinds of code: the "look," represented by the initialization code that sets the window and child window properties, and the "behavior," represented by the event-handling code. As the look is something that you're likely to want handled by someone with artistic sensibilities (a.k.a. "turtleneck-wearing designer types"), whereas the behavior is something you'll want to leave to the coders (a.k.a. "pocket-protector-wearing engineer types"), separating the former from the latter would be a good idea. Ideally, we'd like to move the imperative "look" code into a declarative format suitable for tools to create with some drag 'n' drop magic. For WPF, that format is XAML.

1.1.3. XAML

XAML is an XML-based language for creating and initializing .NET objects. It's used in WPF as a serialization format for objects from the WPF presentation stack, although it can be used for a much larger range of objects than that. Example 1-8 shows how our Window-derived class is declared using XAML.

Example 1-8. Declaring a Window in XAML
<!-- Window1.xaml -->
<Window
  x:Class="MyFirstAvalonApp.Window1"
  xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
  xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
  Text="Hello, Avalon">

    <Button
      x:Name="button"
      Width="200"
      Height="25"
      Click="button_Click">Click me, baby, one more time!</Button>
</Window>

The root element, Window, is used to declare a portion of a class, the name of which is contained in the Class attribute from the XAML XML namespace (declared with a prefix of "x" using the "xmlns" XML namespace syntax). The two XML namespace declarations pull in two commonly used namespaces for XAML work, the one for XAML itself and the one for WPF. You can think of the XAML in Example 1-8 as creating the partial class definition[*] in Example 1-9.

[*] Partial classes are a new feature in C# 2.0 that allow you to split class definitions between multiple files.

Example 1-9. C# equivalent of XAML from Example 1-8
namespace MyFirstAvalonApp {
  partial class Window1 : Window {
    Button button;
  
    void InitializeComponent(  ) {
      // Initialize Window1
      this.Text = "Hello, Avalon";

      // Initialize button
      button = new Button(  );
      button.Width = 200;
      button.Height = 25;
      button.Click += button_Click;

      this.AddChild(button);
    }
  }
}

XAML was built to be as direct a mapping from XML to .NET as possible. Generally, every XAML element is a .NET class name and every XAML attribute is the name of a property or an event on that class. This makes XAML useful for more than just WPF classes; pretty much any old .NET class that exposes a default constructor can be initialized in a XAML file.

Notice that we don't have the definition of the click event handler in this generated class. For event handlers and other initialization and helpers, a XAML file is meant to be matched with a corresponding code-behind file , which is a .NET language code file that implements behavior "behind" the look defined in the XAML. Traditionally, this file is named with a .xaml.cs extension and contains only the things not defined in the XAML. With the XAML from Example 1-9 in place, our single-buttoned main window code-behind file can be reduced to the code in Example 1-10.

Example 1-10. C# code-behind file
// Window1.xaml.cs

using System;
using System.Windows;
using System.Windows.Controls;

namespace MyFirstAvalonApp {
  public partial class Window1 : Window {
    public Window1(  ) {
      InitializeComponent(  );
    }

    void button_Click(object sender, RoutedEventArgs e) {
      MessageBox.Show(...);
    }
  }
}

Notice the partial keyword modifying the Window1 class, which signals to the compiler that the XAML-generated class is to be paired with this human-generated class to form one complete class, each depending on the other. The partial Window1 class defined in XAML depends on the code-behind partial class to call the InitializeComponent method and to handle the click event. The code-behind class depends on the partial Window1 class defined in XAML to implement InitializeComponent, thereby providing the look of the main window (and related child controls).

Further, as I mentioned, XAML is not just for visuals. For example, there's nothing stopping us from moving most of the definition of our custom MyApp class into a XAML file, as in Example 1-11.

Example 1-11. Declaring an Application in XAML
<!-- MyApp.xaml -->
<Application
  x:Class="MyFirstAvalonApp.MyApp"
    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
    StartingUp="AppStartingUp">
</Application>


This reduces the MyApp code-behind file to the event handler in Example 1-12.

Example 1-12. Application code-behind file
// MyApp.xaml.cs
using System;
using System.Windows;

namespace MyFirstAvalonApp {
  public partial class MyApp : Application {
    void AppStartingUp(object sender, StartingUpCancelEventArgs e) {
      Window window = new Window1(  );
      window.Show(  );
    }
  }
}

You may have noticed that we no longer have a Main enTRy point to create the instance of the application-derived class and call its Run method. That's because WPF has a special project setting to specify the XAML file that defines the application class, which appears in the msbuild project file, as in Example 1-13.

Example 1-13. Specifying the application's XAML in the project file
<!-- MyFirstAvalonApp.csproj -->

<Project ...>
  <PropertyGroup>
    <OutputType>winexe</OutputType>
    <OutputPath>.\</OutputPath>
    <Assembly>1st.exe</Assembly>

  </PropertyGroup>
  <ItemGroup>
    <ApplicationDefinition Include="MyApp.xaml" />
    <Compile Include="Window1.xaml.cs" />
    <Compile Include="MyApp.xaml.cs" />

    <Reference Include="System" />
    <Reference Include="WindowsBase" />
    <Reference Include="PresentationCore" />
    <Reference Include="PresentationFramework" />
    <Page Include="Window1.xaml" />
    <Page Include="MyApp.xaml" />

  </ItemGroup>
  <Import Project="$(MsbuildBinPath)\Microsoft.CSharp.targets" />
  <Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>

The combination of the ApplicationDefinition element and the WinFX-specific Microsoft.WinFX.targets file produces an application entry point that will create our application for us. Also notice in Example 1-13 that we've replaced the MyApp.cs file with the MyApp.xaml.cs file, added the Window1.xaml.c file, and included the two corresponding XAML files as Page elements. The XAML files will be compiled into partial class definitions using the instructions in the Microsoft.WinFX.targets file.

This basic arrangement of artifactsi.e., application and main window each split into a XAML and a code-behind fileis such a desirable starting point for a WPF application that creating a new project using the Avalon Application project template from within Visual Studio 2005 gives you just that initial configuration, as shown in Figure 1-5.

Figure 1-5. The result of running the Avalon Application project template



©2008 FAQ - WPF Labs - Discuss - Terms of Use - Privacy Policy - About WPF
- Interview Questions - Sharepoint Articles - Interview Questions Resource Library - All about LINQ - MS Knowledgebase Articles - Electronics and Hardware discussions