1. Computing

Windows Presentation Foundation (WPF) Layout and VB Code

A short article that shows how to avoid NaN code failures


Updated November 14, 2008

If you don't recognize "WPF" or "XAML" then you might want to check out this introduction to the next generation of technology from Microsoft that is being used to create the visual output from your computer. This is the technology that made Vista look completely different and it will make presentation look different in Microsoft software from now on. This article assumes that you know the basics of WPF, such as the fact that a WPF window is created from both a XAML file and a code file written in a language like VB.NET.

The Problem

I was recently working on a simple WPF application and I ran into a very unexpected error.

My XAML code looked like this:

<Canvas Name="myCanvas" Height="300" Width="300">
   <Button Name="Button1"
      Height="25" Width="75">Button</Button>

And the VB.NET code looked like this:

Dim myLine As Line = New Line
myLine.X1 = myCanvas.Width

No problem! But then I changed the XAML code to this:

<Canvas Name="myCanvas" Margin="25,25,25,25">
   <Button Name="Button1"
      Height="25" Width="75">Button</Button>

That is, instead of specifying the Width and Height properties directly, I wanted them to be an offset from the containing panel.

When I ran the program, the VB.NET code crashed with an error message: 'NaN' is not a valid value for property 'X1'. (Actually, there was a lot more code in my app, but I've boiled this down to the essentials here.)

Throwing a QuickWatch on myCanvas.Width revealed that the value in X1 was actually -1.#IND. -1.#IND is probably unfamiliar to a lot of VB programmers because VB has handled this differently in the past. The "IND" refers to "indefinite" as opposed to "INF" which is "infinite". You can even do calculations with this value, but the result is another NaN. The program doesn't actually crash until you try to do something that actually requires a number, such as assigning it to a property that must be an actual number. -1.#IND would pop up as a result in C++ programs, but this is the first time I have seen it in VB. I think this is a result WPF being completely new and still having a few raw edges.

How can the Width be NaN ("Not a Number")? The Canvas displays perfectly in the Visual Studio XAML Designer and the Designer even shows the width. This is the kind of thing that just doesn't happen in Windows Forms.

The problem is that WPF doesn't actually calculate the size of a component like Canvas until it has to. And, evidently, assigning that value to another property ... myLine.X1 in this case ... doesn't trigger the calculation. Using Margin instead of directly setting Width makes it a calculation.

In WPF, "layout" is the process of "measuring and arranging the members of a Panel element's Children collection then drawing them onscreen." Because it can be so intensive with large and complex Children collections, you can't count on WPF always having a valid value in properties like Width anymore.

To compensate for this, there's a new property, ActualWidth (and ActualHeight) that you can also use. This code doesn't crash.

myLine.X1 = myCanvas.ActualWidth

It's worth noting that these properties can be different from the Height and Width properties for a variety of reasons. The layout designer, for example, shows the width as 328 but when I run the code, I get 334 in the ActualWidth property.

Depending on your requirement, you can also use the IsNaN property of the type you're using. (In this case, Double.)

If Double.IsNaN(myCanvas.Width) Then ...

This WPF is a new world!

©2014 About.com. All rights reserved.