Windows Presentation Foundation (WPF)

Windows Presentation Foundation (WPF) is a relatively new technology for creating Windows Graphical User Interfaces (GUI). Unlike Windows Forms, it is not built on top of the system controls – all controls in WPF are custom drawn on the screen using hardware acceleration.

The custom drawing brings an enormous flexibility as to what you can put on the screen using WPF. Basically everything can be customized. You can have an entire application and its controls templated however you like. You are not bound to the standard styles of the operating system.

On the other hand, all this flexibility also makes simple tasks more challenging. When you put a button on a form using Windows Forms for instance, it will automatically style itself depending on the underlying operating system. In WPF all you get out of the box is a simple, not too interesting design of all the basic controls. Making them look more attractive requires you to write your own templates – something you do not have to do in Windows Forms.

One of the main advantages of using WPF is the clear separation of design and functionality. This allows designers in large teams to focus solely on design and developers on the functionality. While you can use Visual Studio to create WPF forms, designers will prefer a tool called Microsoft Blend. In this topic, we will stick with Visual Studio as it provides all of the necessary functionality.

The design part of WPF applications is coded in XAML (Extensible Application Markup language). It is an XML language that is independent of the .NET language and should be easier for designers to understand.

In the following example, we will create a simple WPF application to demonstrate the basics of WPF and XAML.

Simple WPF Application

To create a new WPF Application, start Visual Studio, go to “File” menu and select “New” > “Project”. A new dialog window appears. Select “WPF Application”, type the name of the application and click “OK”:

New Project

The new project gets created. You should see a WPF window designer with its XAML code below:

Designer and XAML

When you look in the XAML code, you will see a <Window> tag and a <Grid> tag inside it. Grid is used for laying out controls in the window as the window can only contain one child element.

We will take a look at the Grid and other panels for control layout later on. Let us now just continue and try to put a simple button inside the grid. To place a new button, use the toolbox and a properties window or just simply put this code inside the grid:

<Button Name="clickMeButton" Content="Click me!" Margin="5" />

We have given our button a name, content and specified a margin. You should now be able to see how the button looks like in the designer.

To add some functionality to our application, we will bind a new event handler to the Click event. The simplest way to do so is to continue typing “Click” attribute in the button. Visual Studio will assist you with name completion as well as event handler creation – always use enter to take advantage of the intellisense options:

Creating Click Handler 1

To create the new event handler, press enter again:

Creating Click Handler 2

You should now end up with the button code looking like this:

<Button Name="clickMeButton" Content="Click me!" Margin="5" Click="clickMeButton_Click" />

A new event handler has been created in the code window. Fill it with a simple code line to show a message box:

MessageBox.Show("Hi there!");

When you run the application now and click the button, you should see the following message box:

Hi There Message Box

The button now takes up all the space of the entire window. To add more controls, we need to make some design changes. We will configure the Grid with three rows and three columns. Add this code right below the <Grid> tag:

<Grid.RowDefinitions>
   <RowDefinition Height="*" />
   <RowDefinition Height="30" />
   <RowDefinition Height="*" />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
   <ColumnDefinition Width="Auto" />
   <ColumnDefinition Width="*" />
   <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

There are basically three types of Height/Width specifications in WPF. When you use a number, the size will be fixed. WPF does not use pixels, however. The number represents so called logical units and one logical unit equals to 1/96 of an inch.

“Auto” makes the size just big enough to fit its contents.

Star (*) always takes the rest of the space. If more stars are used, the remaining space will be split equally among all of them. You can however also specify a ratio with stars – using “2*” and “3*” will divide the remaining space in the 2:3 ratio for example.

In our example, we have created a row of size 30, separated by rows above and below it. This basically makes sure our middle row always get centered vertically in the middle of the window. We also have three columns. The first one will be used for label, the second for textbox and the third for button. The first and last column size will adjust to the size of the label and button respectively. The middle column will take all the remaining space, making the texbox as big as possible.

To put the aforementioned controls inside the grid, replace the existing button code with the following:

<Label
   Grid.Row="1"
   Grid.Column="0"
   Name="nameLabel"
   Content="Name:"
   Padding="5" />
      
<TextBox
   Grid.Row="1"
   Grid.Column="1"
   Name="nameTextBox"
   Margin="5" />

<Button
   Grid.Row="1"
   Grid.Column="2"
   Name="clickMeButton"
   Content="Click me!"
   Margin="5"
   Click="clickMeButton_Click" />

Notice how we need to specify where the control should be placed inside the grid using the Grid.Row and Grid.Column attributes. If the grid position is not specified, 0 is used by default. With this in mind, you can safely omit the Grid.Column = “0” row above in the label definition. It was included in the code just for illustration.

To make the application greet you by the name from the textbox, replace the code in the Click event handler with this:

MessageBox.Show("Hi " + nameTextBox.Text + "!");

When you run the application, you should see something similar to this:

Simple WPF Application - running

When you type your name in the textbox and click the button, the application will greet you through the message box.

The complete source of the Simple WPF Application is available for download.

Basic panels for WPF layout

In the previous example, we have used the Grid panel for laying out controls on the window. There are actually more of these panels available. Let us touch on four of the most commonly used ones, including the Grid panel.

Stack Panel

Stack Panel allows for simple vertical or horizontal alignment of its children. This XAML code

<StackPanel>
   <TextBlock Margin="5" FontSize="20">Click below:</TextBlock>
   <Button Margin="5">Option 1</Button>
   <Button Margin="5">Option 2</Button>
   <Button Margin="5">Option 3</Button>
</StackPanel>

produces this result:

Stack Panel

Dock Panel

Dock Panel pushes its children to the left, top, right and the bottom of itself. Left is the default side when no Dock property is specified. You can also specify that the last child of the Dock Panel fills the rest of the content. This example

<DockPanel LastChildFill="True">
   <Button Content="Left"/>
   <Button Content="Top" DockPanel.Dock="Top"/>
   <Button Content="Right" DockPanel.Dock="Right"/>
   <Button Content="Bottom" DockPanel.Dock="Bottom"/>
   <Button Content="Fill The Rest"/>
</DockPanel>

yields the following result:

Dock Panel

Wrap Panel

Wrap Panel organizes its children either horizontally or vertically. When it reaches the end, it starts again on the new row or column respectively. This is the XAML example:

<WrapPanel Orientation="Horizontal">
   <Button Content="Item 1" />
   <Button Content="Item 2" />
   <Button Content="Item 3" />
   <Button Content="Item 4" />
</WrapPanel>

And this is the result:

Wrap Panel

Grid Panel

We have already seen how the grid panel works in the example above. Let us look at yet another XAML example:

<Grid>
   <Grid.RowDefinitions>
       <RowDefinition Height="Auto" />
       <RowDefinition Height="*" />
       <RowDefinition Height="50" />
   </Grid.RowDefinitions>
   <Grid.ColumnDefinitions>
       <ColumnDefinition Width="*" />
       <ColumnDefinition Width="100" />
   </Grid.ColumnDefinitions>

   <Button Grid.Row="0" Grid.Column="0" Content="H: Auto | W: Rest" />
   <Button Grid.Row="2" Grid.Column="1" Content="H: 50 | W: 100" />
</Grid>

This is the result:

Grid Panel

WPF positioning and sizing

Unlike in Windows Forms, in WPF you should never use Top and Left properties to specify controls positions. Always use the panels discussed above to achieve a responsive design. To influence the controls position even further, use Margin, Padding and Alignment properties.

You can find examples of using Margin and Padding in the examples above.

App.xaml

Unlike Windows Forms or Console applications, WPF Application does not have a Program.cs file by default. There is an App.xaml file instead.

You can use App.xaml to define application-wide resources, bind to global application events as well as change the initial WPF window that gets opened.

Resources

WPF makes it easy to specify resources that you can use repeatedly at various places of your code. The resources can be used in XAML as well as in the code itself.

To add a new resource to the whole application, add this code within the <Application.Resources> tag in the App.xaml file:

<sys:String x:Key="Name">Joe</sys:String>

The “sys” prefix should point to System namespace, where String class is defined. You can achieve this by adding this line to the Window tag attributes:

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

You can now go ahead and use the resource anywhere in the application. You can create a new label in a WPF window for example and have its content filled in by the resource:

Content="{StaticResource Name}"

To access the resource in code of the same window, use this code:

MessageBox.Show(this.FindResource("Name").ToString());

In addition to the static resource we have used above, you can also use dynamic resources. The main difference is that the static resource gets evaluated when the XAML is parsed while the dynamic resource is evaluated when the value is actually needed. Unlike static resources, the dynamic resources also updates the target whenever the resource changes.

Advanced Wpf Application

There are many WPF controls available. As these controls have various properties, events, etc., it is beyond the scope of this topic to describe them all. For more information, use MSDN documentation on specific controls.

To see how combobox and grids are used, you can also examine the Advanced Wpf Application code to see how you can build an identical application to the one we built in the Windows Forms topic:

Advanced WPF Application

Wpf Examples Application

There is yet another WPF example application available for demos on styles, triggers, user controls, custom controls, etc.:

Wpf Examples Application

Download the Wpf Examples Application to try the demos yourselves.

This is the last page of this topic.

Go up to: Windows Applications


Should you have any questions or found a mistake that needs correcting, feel free to send an email to: info [at] mycsharp [dot] net


Advertisements :