Blog Archives

Moving From WinForms to WPF

I’ve written lots of blog posts about WPF and in most cases the selection of topics has been a bit random.   Essentially, if it interests me at the time I’d write about it.  The problem with that approach is that it might assume a more basic grasp of WPF than many readers have.

In a recent post on VB City, someone said (in a discussion about WPF): “I don't know where to start and a WPF primer would be good”.  Not knowing where to start is probably a common problem, so I plan to write a few blog posts that will take a WPF 101 approach.  I’ll still be writing the higher level blogs in between times, but hopefully this series will be useful to those who are familiar with WinForms and want to see the specific differences between WinForms and WPF.

To make the blogs’ content accessible to the widest range of readers, I’ll base the samples on the VB Express version.  Today we’re still at VB2008, but VB2010 will be along in a few weeks and I’ll switch to that when it happens. I’ll also try and flag up any important differences between the 2008 and 2010 versions.

So let’s get started.

Create a new WPF project

Start a new project and select the WPF Application template:

WPF101_1_001

I’ve named it WPF101_1.

Check out the IDE

The view in the IDE is similar to the one for WinForms, but there are some obvious differences.

WPF101_1_002

The first major change from WinForms is the way that the design area is split.  The top half still shows the design view of the ‘Form’ (now a Window in WPF, but very similar in role to a Form). Below that, there’s the XAML pane.

XAML is a version of XML that you can use in WPF to design elements. We’ll be looking at XAML in much more detail as we progress, but for now remember that you don’t have to be an expert in XAML to be able to create some very useful and good WPF applications. In fact you could create everything using Visual Basic, although this isn’t the most efficient way of doing it.

The list of items in the Solution Explorer is also slightly different. There are new file types listed – specifically by default Application.xaml and Window1.xaml.  Both those XAML files have a plus sign next to them. When you click on the plus sign, a second file with the extension of xaml.vb appears. In general, the role of the XAML files is to hold the markup that represents the look of the elements in the project. The xaml.vb file, which is usually referred to as the code-behind file, generally deals with the behaviour. Their roles are a lot more flexible than that, but it’s a reasonable way of thinking of them at this early stage.

The Toolbox at the left hand side of the IDE is similar to the WinForms one.

WPF101_1_003

Many of the names of the controls are the same in both WinForms and WPF. This is both a good and bad thing. It’s good because you’ll be familiar with them. It’s bad because there are often differences that will catch you out if you’re not aware of them.

Create a Hello World! Window

1.  Add a Button to the Window

As a start point, I’ll create the canonical Hello World! app.  From the ‘Common’ tab of the Toolbox, select and drag a Button on to the surface of the Window. A key difference between WPF and Winforms when you do this is that you will see that some additional XAML is added to the XAML pane below the Designer.

WPF101_1_004

Your version won’t be exactly the same. The Margin values, for instance, are likely to be different. Also, I’ve split up the original into three lines just to reduce the width of the screenshot.

The XAML markup you see there between the opening and closing tags creates an instance of a Button. Here’s the Button in the Design pane.

WPF101_1_005

 

Looking at the things you see in the Design and XAML panes, these bring up various WPF specific points :

Nested Content  There are two blue bars at the left and top of the Window, each with a number in them. To understand what these represent, you need to look back at the XAML that was automatically created for this Window. On line 5 you see there is an opening tag for a Grid. On Line 9, there is a closing tag for this Grid. Whenever you create a new Window in the IDE, a Grid will be placed inside the Window in this way. It’s placed there is to act as a container for the remaining content.

One of the features of WPF is that many of the visual elements can only contain a single child. Now, although you may think it’s bizarre at this stage, a WPF Window is one of the elements that can contain only one child element. If that were literally true, the options for useful Windows and user-friendly applications would be very limited. It is true, but the get out clause is that each child element may content sub-elements. And each sub-element may contain its own children and so on. Therefore this isn’t really a limitation at all. We’ll look at why WPF layout is structured in this way later.

In the example so far, the Window has a child element of a Grid and the Grid has a Button as its child.

Grid Markers  Going back to the blue bars, these mark the outside edge of the Grid.  The values represent the height and width of the Grid. You will see in a later blog post how you can the Grid’s blue bars to add columns and rows to a grid.

Resolution Independence   The Button has been given a fixed Height value of 23 and a Width of 75 pixels. You should note that these aren’t the standard screen pixels that you are used to in Winforms. They are what is known as ‘device independent units’.  Confusingly, they are often referred to as ‘device independent pixels’, which almost inevitably results in them sometimes being referred to as just plain old ‘pixels’. But they are different from the pixels of your Winforms applications.

The device independent pixel of WPF respects the Dots Per Inch (DPI) setting of the system it is using. What this means in reality is that if you create your WPF button and deploy the application to a system that has a higher DPI setting, WPF will use more than ‘your’ 23 and 75 pixels to render it.   The effect of this is that the button will be as crisp on a machine with a different DPI setting as it is on yours. You don’t get that scrunching up of the elements that you often see in this situation. 

What happens is that WPF’s rendering engine makes full use of the available pixels on the deployed system. So if the machine the application is deployed on has a System DPI of, say, 120 then WPF would use 29 of those higher density pixels for the height and 94 for the width (approximately), rather than the original 23 and 75.   This is different from the blocky “fill in the extra pixels and get a jaggy result” effect that you will have seen elsewhere. Because WPF renders everything on screen using vector graphics, you simply get a higher density version of the original.

Margins   The XAML markup shows the Margin property for the Button. The four values represent the distance in device independent units that this button will always be from the edges of its parent. In the current example, it is 48 units from the left edge of the Grid and 40 units from the top. If you drag the button around in the Design pane, then let go, you’ll see that the values of the Margin property settings will change to reflect where you’ve left the Button.  The four values in the Margin setting represent Left, Top, Right, Bottom – always in that order. 

Alignment   You’ll also have noticed the two arrow pointing from the Button to the edge of the Grid. These signify that the Button is horizontally aligned to the left and vertically aligned to the top. This is also confirmed in the properties shown in the XAML. You can think of this as being the same as the Anchor properties in Winforms. WPF however offers much more subtle options than just plain anchoring.

if you did try dragging the button around in the Design pane, you’ll probably have found that, quite confusingly, not only do the top and left margin values change, but you might also see either the HorizontalAlignment, the VerticalAlignment, or both of them, disappear from the XAML. The reason for this is that WPF has a very sophisticated layout toolset that you can use directly in the Design pane. (You can of course manually make changes to the XAML, but because this is Winforms –> WPF, I’m going to try and use minimal hand coding of XAML.)

Looking at my original screenshot of the Window, you’ll see that at the right and bottom of the Button there is a small circle. Hover over the one at the right and you’ll see a hand icon appear.  It can be a bit fiddly, so make sure you have the hand, not the double-headed arrow.  If necessary, use the excellent Zoom scaling tool in the top left hand corner of the Design pane to increase the size of the display.

WPF101_1_006

 

Now, click on the circle and three things will happen. The circle will go and be replaced by another arrow, this one pointing to the right hand edge of the grid.  The third value in the Margin property down in the XAML pane will change from  to a new value.  Finally, the HorizontalAlignment property will disappear from the XAML.

The result of this change will be that if you run the project and change the size of the Window, the Button’s width will change so that it is always the same distance from the left and right edges. So at this point you have three-way anchoring.

Vertically, there will be no change if you alter the size of the Window, because the HorizontalAlignment is still set to Top and there is a constant Margin of 39 units between the top of the Button and the top of the Grid. Obviously, if you click on the circle at the bottom of the button, this will make a similar change to the vertical settings.

If you click on any of the arrows, they will change to circles.  This is a feature you need to experiment with in order to become totally familiar with it.

Button Content  You’ll see the word ‘Button’ located between the opening and closing tags of the Button element markup. The same word also appears on the face of the button in the Design pane. In a similar way to how Winforms assigns a default Text property of ‘Button1’ to a button, WPF assigns a default Content property of a string containing the word ‘Button’.  Note that it’s not a Text property, as in Winforms, even though in this case it does happen to be text.  In WPF, Content is everything. A WPF button can have almost any content. The limitations of text and an image are gone. If you remember my explanation above of nested content, this applies equally to buttons. So a button can contain layers of nested content. I’ll be covering the possibilities of this later, but for now just keep in mind that it’s Content and not Text.

WPF controls have default properties and the default property of a button is Content. Because of this, the XAML is displayed in the way you first saw above. I think the IDE maybe does you a disservice here by doing this. Another way of more specifically identifying the Content is to include its property value within the opening tag:

WPF101_1_007

 

So, even with something as basic as a button, you’ll see that there are already important differences between Winforms and WPF.

2.  Add a TextBlock to the Window

Expand the ‘Controls’ tab in the Toolbox and scroll down until you reach the TextBlock. Drag one on to the Window’s surface.

WPF101_1_008

 

Again you will see the alignment arrows and, as before with the button, you change these settings.

The default Property of a TextBlock is the Text property. When first created, the TextBlock is empty. You can enter text for the TextBlock either by placing it between the opening and closing tags or by specifically assigning a value to the Text property.

<TextBlock Height="21" Margin="39,0,62,38" Name="TextBlock1"
VerticalAlignment="Bottom" Text="This is a TextBlock" />

For the sake of completeness, I should tell you that it is possible to include other sub-elements inside a TextBlock. And these don’t even have to be text. That said, there are many better options for cases where you want to mix text and other graphical elements, so my advice is to stick to using the TextBlock for plain text. Well, not plain text – WPF offers you a lot of options for enhancing the look and style of text.  I’ll cover these choices later.

The WPF TextBlock is a Read Only control. If you want to take text input from a user, a TextBox, similar to the WinForms one, is available. You may have noticed that there is a Label element available in the Toolbox. I could have used this and it would have worked fine, but I chose the TextBlock because for most purposes in WPF apps it’s a better option.

3.   Add the Button’s Event Handling Code

In many cases, you can do what you probably do with a Winforms button in order to create and access its Click event. You double-click on the button in the Design pane.  This will automatically create the event handler code which include the familiar ‘Handles’ clause at the end of the signature line. In this example, ‘Handles Button1.Click’. It also brings up the xaml.vb code-behind file in the IDE to allow you to start adding code.

There is also an alternative. Back in the XAML for the Button, you can add a Click property inside the Button’s opening tag. When type in ‘Click=’ you will get a context menu:

 

WPF101_1_009 

 

In the above screenshot, the menu only contains the one choice of New Event Handler. If the code-behind file contains other procedures, these will also be listed as choices. When you double-click on the New Event handler choice an event handler will be created for you in the code-behind. This procedure won’t include the Handles clause.  The Handles clause isn’t needed for our Button1 instance, because it is already wired up via the Click property in the XAML.

As for the VB code in the event handler, this will be:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)

        TextBlock1.Text = "Hello World!"

    End Sub

Apart from the new WPF control, the syntax will be familiar, i.e. assigning a value to the Text property. The code differences between Winforms and WPF unfortunately won’t always be this simple, but I’ll try and cover many of the Gotchas as we come to them.

Change the Heading of the Window

In Windows Forms, you set the Text property of a Form to change what is shown as its heading. In WPF, the Window has a Title property that does the same thing. You’ll find this within the opening tag of the Window in the XAML pane.

WPF101_1_010

You can edit it there or you can select the Window in either the Design or XAML panes and then change the value of the Title property in the Properties pane. 

Run the Project

When you run the project and click on the Button, the event handler in the code-behind will populate the TextBlock with the Hello World string.

WPF101_1_011

Other Points

  Reloading.  You’ll often find that you see a gold bar at the top of the Design pane that says “An assembly or related document has been updated which requires the designer to be reloaded. Click here to reload”. You need to click on this before continuing. This message will appear whenever you make a change (usually in the code-behind or elsewhere in the project) and the layout engine needs to figure out how that affects what it’s going to show you as a result of the change. 

  Properties Pane.   The Properties pane is available to you in the same way as in Winforms.  You can click on an element either in the Design pane or the XAML pane and its properties will appear in the Properties pane, where you can view or edit them.  So you don’t even need to edit the XAML in most cases if you’re more comfortable using the Properties pane. 

 

 

 

Summary

In this first article, you’ve seen some of the differences between WPF and Windows Forms. There’s still an awfully long way to go and many differences to learn about, but at least we’ve made a start.

Some coverage of the following topics has been included:

 

  • Alignment
  • Button
  • Code-behind
  • Event Handling
  • Grid
  • Label
  • Margins
  • Nested content
  • Properties Pane
  • Reloading Message
  • Resolution Independence
  • TextBlock
  • TextBox
  • Window Title
  • XAML pane

WP Like Button Plugin by Free WordPress Templates