LearnWPF Interview with Michael Latta

29. April 2006

Last week I spoke to WPF MVP Michael Latta about his experiences developing WPF applications. Michael is a 30-year veteran of the IT industry with experience on a number of different platforms including Java and Smalltalk. He is also a frequent contributor to the WPF forums. You can download the interview here [4.1 MB].

Related Urls:

Windows Presentation Foundation Design Guidelines draft released on MSDN

25. April 2006

A draft set of design guidelines for WPF has been published on the MSDN, to help developers and designers make appropriate design choices when creating user interfaces. In conjunction with the UX guidelines for Windows Vista this should help weilding the enormous power of WPF to create great UIs. The guidelines help developers/designers to consider their UI based on the type of application they intend to create: productiviy application, kiosk app, utility etc. Then it offers prescriptive advice per feature set of WPF detailing what is good, and what to avoid.

[via Andrew Stopford]

How do I prevent BamlParseExceptions when binding some object properties?

20. April 2006

WPF's data binding facilities are extremely powerful - sometimes when using this power you may experience BamlParseException with an error message stating that the was a problem converting from a Binding object to some other type. A typical error message might look like this:

Error at element 'RuntimePropertyInfo' in markup file 'Window1.xaml' : Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'

This problem can be confusing at first because Elements with the same DataContext in your Xaml file may be able to bind to the same piece of data without any problems.

<Window.Resources>
  <XmlDataProvider x:Key="data" XPath="//item">
    <x:XData>
      <items >
        <item val="foo"/><item val="bar" />
      </items>
    </x:XData>
  </XmlDataProvider>
</Window.Resources>
<StackPanel>
  <!-- this works -->
   <TextBlock Text="{Binding
XPath=@val }" />
  <!-- this does not -->
  <TextBlock>
    <Bold Text="{Binding
XPath=@val}"/ >
  </TextBlock>

</StackPanel>

If this is the case it can be indicative of a subtle problem not with the source of the data but with the property you're trying to bind the data to. WPF data binding makes use of the dependency property system built into WPF, and the eventual target of the {Binding} markup extension must be a dependency property. Dependency properties are not the same as CLR properties, which are a syntactic convenience which allows a pair of get and set methods for a member to be treated from a code perspective like a member field. Dependency properties on the other hand are objects of type DependencyProperty. Most of the UI-related properties of controls in WPF eventually call dependency properties internally, so it is easy to forget this rule.

It is not easy to know at a glance if a CLR property does indeed call a dependency property or not. The current WPF documentation does not explicity indicate this. The documentation does list the public fields of an object, which typically includes all the dependency properties as static fields. If the property you're trying to bind to does not have a static DependencyProperty member variable with the name of the CLR property, followed by 'Property' (e.g. TextProperty) then the CLR property is unlikely to be using the dependency property system underneath, and thus is not a suitable target for binding. Using Reflector to look inside the property getter and setter methods it is easy to spot the difference between the two.

CLR Property which calls a DependencyProperty (TextBlock.Text)

public string Text
{
      get
      {
            return (string) base.GetValue(TextBlock.TextProperty);
      }
      set
      {
            base.SetValue(TextBlock.TextProperty, value);
      }
}

CLR Property which does not call a DependencyProperty (Bold.Text), which we cannot bind to.

public string Text
{
      get
      {
            return TextRangeBase.GetTextInternal(base.ContentStart, base.ContentEnd);
      }
      set
      {
            if (value == null)
            {
                  value = string.Empty;
            }
            TextContainer container1 = base.TextContainer;
            container1.BeginChange();
            try
            {
                  TextPointer pointer1 = base.ContentStart;
                  if (!base.IsEmpty)
                  {
                        container1.DeleteContentInternal(pointer1, base.ContentEnd);
                  }
                  Run run1 = Inline.CreateImplicitRun(this);
                  pointer1.InsertTextElement(run1);
                  run1.Text = value;
            }
            finally
            {
                  container1.EndChange();
            }
      }
}


In some cases it is possible to work around this problem - if you are using data binding to keep two things synchronized and the other thing is a dependency property then swapping the source and target of the binding can solve this problem.

Simple Styles - elegant, simple WPF control styles by Robert Ingebretsen

18. April 2006

Robert Ingebretsen (WPF program manager) has released a version of his Simple Styles for the Feb CTP of WPF. The styles provide great examples of how to alter the appearance of the common WPF controls including

  • Button
  • CheckBox
  • ComboBox
  • Expander
  • GroupBox
  • Label
  • ListBox
  • ListView
  • Menu
  • ProgressBar
  • RadioButton
  • ScrollBar
  • Slider
  • Tab
  • TextBox
  • Tooltip
  • TreeView

The styles are well-factored into a single Xaml file for each control type. If you're looking at writing custom styles for any of the built-in controls, or just want some simple and attractive styles to use in your application you should definitely use these as a starting point.

 WPF Simple Styles in action

Professional WPF Programming from Wrox Press is available for pre-order

16. April 2006

Professional WPF Programming : .NET Development with the Windows Presentation Foundation from Wrox Press is available for pre-order on Amazon. This title is co-authored by Scott Van Vliet, Shawn W. Livermore and Chris Andrade. The book will be around 650 pages and is due for release in early October 2006. None of the authors are notable figures in the WPF community, however by limiting the number of co-authors to 3 this book will hopefully not suffer from the weaknesses that plague other books in the series that are co-authored by dozens of authors and lack cohesion. The book description raises a number of other interesting questions - frequent mentions of ASP.NET and talk of "built-in server controls" and mention of "Ajax/Atlas" makes the book sound at best like a very web-centric view of WPF, and at worst fundamentally misguided about what WPF is really about. Hopefully the final book will be better written than the current description that appears on Amazon.

How do I fix the inexplicable "Item has already been added" errors with resource dictionaries in WPF?

15. April 2006

Occasionally when developing WPF applications you may experience an inexplicable error regarding duplicate keys in a ResourceDictionary. The wording for the error will be something like the following:

Error at element 'ResourceDictionary' in markup file 'Window1.xaml' : Item has already been added. Key in dictionary: 'MyItemKey'  Key being added: 'MyItemKey'.

This is a perfectly valid error message if you are actually adding a second item to a dictionary with a key that has already been used. What makes this error confusing is that it can occur in simple applications when there are obviously no duplicates in the dictionary in question. The error occurs at run-time, but seems to be caused by some bug in the WPF build process. The problem can be worked around in a number of cumbersome ways such as re-naming the single resource in question, or copying files into a new project. The recommended way to solve this problem is to select 'Clean' from the build menu and then re-build your application. This problem has been noted in versions of WPF including the current Feb 2006 CTP. Hopefully this issue will be resolved as WPF approaches its final release.

Performing a Clean from the VS context menu

What parts of my WPF windows are drawn by WPF?

15. April 2006

Not all of your application's window is actually drawn by WPF - In order to integrate with the underlying operating system the border and title bar of WPF windows are still drawn in GDI like other windows. This means that some operations that can be performed on most elements in WPF (like LayoutTransforms and RenderTransforms) cannot be applied to the top-level window element. This also means the rendering of these areas cannot be customized in WPF in the way that normal elements can be using styles or templates. In order to create customized title bars for your windows you have to create a borderless window, and create a title bar yourself in Xaml. 

This gets slightly more complicated on Windows Vista, where rendering of form borders and title bars is handled by the Desktop Windows Manager (DWM) which uses a component called MILCore (MIL stands for Media Integration Layer), which calls into DirectX. It turns out WPF uses this same graphics stack to render. WPF's PresentationCore calls into MILCore (which is unmanaged) which then calls into DirectX. While this implementation detail is interesting to know from a programming point of view the outcome is the same on Vista as XP and Windows 2003 - you can't change the appearance of the title bar or scale, skew or rotate your whole windows from WPF using transforms.

Another implication of this is controls on your WPF forms no longer have a window handle (hWnd), since they are not rendered by GDI. Unless you are hosting controls from Windows Forms or MFC the only hWnd in your typical WPF application will be the hWnd of the top-level window. This means UI automation and testing technologies that rely on hWnds to programmatically drive your UI will nolonger work. Fortunately WPF comes with its own UI automation API.

The other region of your WPF windows that will not actually be rendered by WPF are any controls from other presentation frameworks like WindowsForms or MFC that are being hosting inside an HwndHost - they are still rendered by GDI. This also means you can't scale, skew, translate or rotate them using transforms.

Charles Petzold's WPF Book - "Applications = Code + Markup" available for pre-order

8. April 2006

The godfather of Windows UI programming Charles Petzold has been writing a book on WPF programming for some time now. Fortunately the book is available now for pre-order from Amazon. The book will weigh in between 800 and 900 pages with approximately 36 chapters devided into 3 sections: Code, Markup and Applications (which ties back in nicely to the title). The contents of the book are detailed here, and you can read code samples from the book and details of topics covered on Charles' weblog. If previous books from the author are anything to go by this book should give in-depth coverage of the WPF platform. The book is scheduled to ship in Q3 or Q4 2006. Charles has been writing books on Windows UI programming since 1988, which saw his "Programming Windows 1st Edition", and its subsequent editions are considered the definitive works on Win32 UI programming.

Applications = Code + Markup book cover

How can I control the layout of items in WPF?

5. April 2006

WPF attempts to bring the best of rich-client technologies like Windows Forms, and layout techniques from the browser to give a high degree of flexibility when positioning elements on forms.

Rich client technologies like VB6 forms, Access Forms etc were based on absolute positioning. As a developer you specified the top and left values for a control to position it on the form. This allows for a fine degree of control, but often required a large amout of code to handle form re-sizing. This was an imperative approach to layout. Controls like Labels and Panels had no awareness of the size of the content inside them - for example if the content of a label was larger than what could be displayed in the label then the content is clipped, and not shown.

Web UI rendered in the browser typically require no re-sizing code. Instead HTML gives a declarative approach to the layout of elements. You specify a serise of containers like <div> elements (or <table>, <tr> and <td> elements if you haven't become convinced of the benefits of positional CSS-based layouts) and position those by either floating them Left or Right, or positioning them absolutely in your page. Elements like <div> are aware of the size of their contents and will stretch to accomodate their content.

Both these approaches could be equally difficult to achieve the desired layout, although the declarative approach had the advantage of requiring much less code to do so. Recently windows forms has added concepts like Docking and Anchoring, adding a more declarative approach to rich-client development. WPF continues this trend with a declarative approach to layout based on the concept of panels.

Most UI elements in WPF can only contain a single child element - for example the following Xaml code fails to compile with the following error: "The 'Button' object already has a child and cannot add 'CheckBox'. 'Button' can accept only one child."

Xaml Syntax (does not compile)
<Button>
 <TextBlock>Some Text...</TextBlock>
 <CheckBox />
 <ComboBox />
</Button>

If the button allowed these two elements to be nested inside it it would be responsible for laying them out somehow. Since there are many possible ways these items could be layed out the button would have to become a much more complicated control to accomodate them all, and would now have two "responsibilities" - allowing the user to click on it, and laying out content. Not only would the button become much more complicated but all the controls in WPF would become more complicated. Instead of taking this approach the WPF team decided to factor out the responsibility for layout to a different control - the panels. There are a number of different types of panels in WPF and each enables a different kind of layout. Panels can be nested wherever regular content can be placed, allowing a fine degree of control over the layout of items. For example to correct the problem in the example above we could nest a StackPanel inside the button, and position the elements inside the StackPanel

<Button>
 <StackPanel>
  <TextBlock>Some Text...</TextBlock>
  <CheckBox />
  <ComboBox />
 </StackPanel>
</Button>

This give the following layout:

Button with nested items (stacked)

Having briefly introduced the important role panels play in controlling layout in WPF let's look at the most commonly used panel types and their characteristics.

StackPanel
The StackPanel lays out child elements by stacking them one after the other. Elements are "stacked" in the order they appear in the Xaml file (document order in XML terms). Items can either be stacked vertically (the default) or horizontally.

Xaml Syntax for Stacking Vertically (Feb 2006 CTP):
<StackPanel>
  <TextBlock FontSize="16"
             Foreground="#58290A">
    Items inside a StackPanel</TextBlock>
  <Button>Item 2</Button>
  <Border BorderBrush="#feca00" BorderThickness="2">
    <TextBlock>Item 3</TextBlock>
  </Border>
</StackPanel>

Content in a stack panel (vertical)

Xaml Syntax for Stacking Horizontally (Feb 2006 CTP):
<StackPanel Orientation="Horizontal">
  <TextBlock FontSize="16"
             Foreground="#58290A">
    Items inside a StackPanel</TextBlock>
  <Button>Item 2</Button>
  <Border BorderBrush="#feca00" BorderThickness="2">
    <TextBlock>Item 3</TextBlock>
  </Border>
</StackPanel>

Items in a StackPanel (horizontal)

WrapPanel
The wrap panel lays out items from left to right. When a row of items has filled the horizontal space available to them the panel wraps the next item around onto the next line (in a similar way to how text is layed out).

Xaml Syntax (Feb 2006 CTP):
<WrapPanel>
  <TextBlock FontSize="16"
             Foreground="#58290A">
    Items inside a WrapPanel</TextBlock>
  <Button>Item 2</Button>
  <Border BorderBrush="#feca00" BorderThickness="2">
    <TextBlock>Item 3</TextBlock>
  </Border>
</WrapPanel>

Items in a WrapPanel

DockPanel
The DockPanel allows elements to be docked to the edges of the panel's container, similar to Windows Forms docking. Items are docked in the order they appear in the Xaml file (document order). The last Border element fills all the remaining space since no DockPanel.Dock attribute is specified for it.

Xaml Syntax (Feb 2006 CTP):
<DockPanel>
  <TextBlock FontSize="16" DockPanel.Dock="Top"
             Foreground="#58290A">
    Items inside a DockPanel</TextBlock>
  <Button DockPanel.Dock="Left">Item 2</Button>
  <Border BorderBrush="#feca00" BorderThickness="2">
    <TextBlock>Item 3</TextBlock>
  </Border>
</DockPanel>

Items in a DockPanel

Canvas
The Canvas panel is similar to the way old rich-client layout worked where you control the absolute position of things by setting a Top and Left property for them. Additionally, instead of setting the Left to position an item you can instead set the Right, or instead of setting the Top you can set the Bottom. If you specify a Left and a Right the Right value is ignored, the element does not change its size to make both these values correct, and similarly Top takes precedence over Bottom. Elements that are declared earlier in the Xaml file can appear behind elements that are declared later (if their positions over-lap).

Xaml Syntax (Feb 2006 CTP):
<Canvas>
  <TextBlock FontSize="16" Canvas.Top="10" Canvas.Left="20"
             Foreground="#58290A">
    Items inside a Canvas</TextBlock>
  <Button Canvas.Bottom="25" Canvas.Right="50">Item 2</Button>
  <Border BorderBrush="#feca00" BorderThickness="2"
          Canvas.Top="20" Canvas.Left="50">
    <TextBlock>Item 3</TextBlock>
  </Border>
</Canvas>

Items in a Canvas

Grid
The Grid panel is an extremely flexible panel, and can be used to achieve almost everything that can be done with the other panel controls (although often not with the same ease). The grid panel allows you to define rows and columns in the grid using Xaml, and then place controls in calls in the grid using grid-specific attributes. Elements can span multiple rows or columns. The grid will automatically make all its rows and columns the same size (based on the size of the content) but you can specify a proportional size for rows and columns using a star notation, or specify an absolute width or height. The star notation can be seen in the example code below where one of the columns is twice the width of the other column by setting the Width attribute to "2*". The example below also shows the height of one row being set to an absolute value. The differences these introduce can more readily be seen when re-sizing the form containing the grid, as the grid will expand by default to fill the space available to it. The example below also has the ShowGridLines attribute of the grid set to True to help you visualize the space each row and column is taking up. A broader range of layout tricks for the grid panel is beyond the scope of this introduction, but hopefully we'll be able to re-visit this soon in a future article.

Xaml Syntax (Feb 2006 CTP):
<Grid Margin="10" ShowGridLines="True">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="2*" />
    <ColumnDefinition />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="25" />
    <RowDefinition />
    <RowDefinition  Height="2*"/>
  </Grid.RowDefinitions>

  <TextBlock FontSize="16"
             Foreground="#58290A"
             Grid.Column="0" Grid.Row="0"
             Grid.ColumnSpan="2"

             >
    Items inside a Grid</TextBlock>
  <Button Grid.Column="0" Grid.Row="1">
    Item 2</Button>
  <Border BorderBrush="#feca00" BorderThickness="2"
          Grid.Column="1" Grid.Row="2">
    <TextBlock>Item 3</TextBlock>
  </Border>
</Grid>

Items inside a Grid

We can see from the different examples above that the different Panel controls not only influence the position of the elements they're laying out, but also their size.

Implementing a Custom Panel
The WPF layout system is not limited to the layouts that are included by default. If you need a special layout that can't easily be achieved with the built-in panels you can implement your own. WPF Program Manager Kevin Moore has implemented two custom panels - an animating tile panel and a TreeMapPanel . The source for these built with the February CTP (the most recent at the time of writing) is available here.

How can I display my business objects in a consistent way across different forms in WPF?

30. March 2006

Defining something in a single place for re-use in multiple places is a common goal for developers. In UI frameworks like ASP.NET or windows forms re-using pieces of UI is typically done by creating user controls or custom controls. Unfortunately the places where you can easily use these is often limited. For example if you create a UserControl in ASP.NET to display an employee there is no easy way to re-use that control when displaying a list of customers in a combo box. WPF allows the display of business objects and other data to be templated like controls, and because of WPF's rich content model these data templates can be used in many different places.

Lets look at the steps we would go through to create a simple data template for displaying employee data. First lets assume that our employee type has the following public properties, all of which are strings:

  • Department
  • EmailAddress
  • ImagePath
  • JobDescription 
  • Name
  • Title

We might wish to lay out our employee data as shown below: an image of the employee on the left followed by with the employee name, email address and other details layed out as shown.

desired layout for employee display

In order to create the DataTemplate we'll first examine the regular Xaml to display the layout shown above statically (without any data binding) and then add a little data binding code to turn this into a DataTemplate we can use anywhere we want to show employees. The Xaml markup below creates the static layout we want, with appropriate text placeholders for the fields we'll eventually be exposing from the Employee object. To achieve this layout we used a Grid panel, one of the most flexible layout panels in WPF. We created a 3x3 grid of rows and columns by adding the appropriate <ColumnDefinition/> and <RowDefinition/> elements to the Grid. Then we add the actual placehoders to the Grid - TextBlock elements and a single Image element. We control the placement of these elements in the Grid by setting the Grid.Row and Grid.Column attributes. This notation in the form of ParentElement.PropertyName is called Property-Element syntax. This Xaml is actually setting properties on the parent Grid element, placing child elements in the appropriate rows and columns.

<Grid ShowGridLines="True" Background="Transparent">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="55" />
    <ColumnDefinition />
    <ColumnDefinition />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition />
    <RowDefinition />
  </Grid.RowDefinitions>
  <Image Width="50" Stretch="Uniform"
         Source="pack://application:,,/Media/head-male-sillouette.gif"
         Grid.Column="0" Grid.Row="0" Grid.RowSpan="2"/>
  <TextBlock FontSize="20" Grid.Column="1" Grid.Row="0"
             Foreground="Orange" TextDecorations="Underline"
             Text="Data Bound: Name"/>
  <TextBlock FontSize="12" Grid.Column="1" Grid.Row="1"
             Foreground="Blue" TextDecorations="Underline"
             Text="Data Bound: EmailAddress" />
  <TextBlock FontSize="16" Margin="10,0,10,0" Grid.Column="2"
             Grid.Row="0" Foreground="Black"
             Text="Data Bound: Title" />
  <TextBlock FontSize="16" Margin="10,0,10,0" Grid.Column="2"
             Grid.Row="1" Foreground="Black"
             Text="Data Bound: Department" />
  <TextBlock FontSize="12" Grid.Column="0" Grid.ColumnSpan="3" 
             Grid.Row="2" Foreground="Black"
             Text="Data Bound: JobDescription (this one can span multiple columns)"
             TextWrapping="Wrap" />
</Grid>

To Convert this Xaml into a DataTemplate, all that is required is to change the currently static TextBlock text to something bound to the employee object. This is done with the Binding markup extension {Binding Path=PropertyName}, using the name of the property you wish to mind to in the Path portion of the binding statement. The image source is also just a string, so we can bind the source of the image to that to. We also need to place our Xaml in a DataTemplate element and assign it a DataType. By placing the DataTemplate in the Application resource dictionary in MyApp.xaml we can use this template anywhere in our application we are binding to employee data. The finished data template is shown below. The text in orange shows the changes necessary to convert from static Xaml to the DataTemplate.

<DataTemplate DataType="{x:Type l:Employee}">
  <Grid Background="Transparent">
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="55" />
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>
    <Image Width="50" Stretch="Uniform"
           Source="{Binding Path=ImagePath}"
           Grid.Column="0" Grid.Row="0" Grid.RowSpan="2"/>
    <TextBlock FontSize="20" Grid.Column="1" Grid.Row="0"
           Foreground="Orange" TextDecorations="Underline"
           Text="{Binding Path=Name}"/>
    <TextBlock FontSize="12" Grid.Column="1" Grid.Row="1"
           Foreground="Blue" TextDecorations="Underline"
           Text="{Binding Path=EmailAddress}" />
    <TextBlock FontSize="16" Margin="10,0,10,0" Grid.Column="2"
           Grid.Row="0" Foreground="Black" Text="{Binding Path=Title}"/>
    <TextBlock FontSize="16" Margin="10,0,10,0" Grid.Column="2"
           Grid.Row="1" Foreground="Black" Text="{Binding Path=Department}"/>
    <TextBlock FontSize="12" Grid.Column="0" Grid.ColumnSpan="3" 
           Grid.Row="2" Foreground="Black" Text="{Binding Path=JobDescription}"
           TextWrapping="Wrap" />
  </Grid>
</DataTemplate>

We don't need to do anything special in our application to use the DataTemplate. Any time an element is bound to an employee, or list of employees the DataTemplate will be used. For this example we added an ObjectDataProvider to the Application resource dictionary (in MyApp.xaml) which returns a collection containing 4 employee objects. We then set it as the DataContext for all the items in our main window. Below is the Xaml for binding the contents of a button to a single employee, and for binding a ComboBox to the list of employees. You can download the full source for this sample here.

<StackPanel Margin="10" DataContext="{StaticResource Employees}">
    ...
    <Button Content="{Binding Path=[0]}" />
    <ComboBox ItemsSource="{Binding}" SelectedIndex="0" />
 </StackPanel>

Button and combo box