Visual Studio 2010 help

If you have installed Visual Studio 2010 and look for a decent help functionality, then you will probably be just as disappointed as I was. The new help system is back to the stone ages, because it doesn’t have a decent index or search functionality. Most people, including me, revert to Google to access the online MSDN system.

Fortunately, the API is much richer than the GUI that shows the help and Rob Chandler created Help Viewer for VS 2010 and it looks quite promising:

Help Viewer for VS 2010

Microsoft created a great product with VS 2010 and the .NET framework, so I don’t understand the philosophy behind this help viewer. Didn’t the team have enough time to create a decent help viewer or is it something else?

Organizing Generic.xaml

Creating controls in WPF seems difficult at first. The separation between code and the appearance of the control is one of the great WPF features, but it requires a different way of thinking about controls. The code is located in its own folder and namespace, but the control default style is defined in the Generic.xaml file (or one of its themed cousins) that is located in the project’s Themes directory.

Although the behaviour (code) and its appearance (style) are completely separated, you still work on both of them at the same time. So it would be convenient to have these files close together. Another problem of the Generic.xaml file is that it tends to get very large, when you have a lot of (complex) controls. Fortunately, there is a good way to solve this issue.

Default styles need to be defined in the Theme\Generic.xaml (or one of its themed cousins). Nothing you can do about that, but you can make the generic resource dictionary a merged dictionary that loads other dictionaries that you can put on arbitrary places.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/RamonDeKlein.Controls;component/AsyncLoadControl/AsyncLoadControl.xaml"/>
        <ResourceDictionary Source="/RamonDeKlein.Controls;component/AnimatedSizeControl/AnimatedSizeControl.xaml"/>
        <!-- include other definitions here -->
    </ResourceDictionary.MergedDictionaries>

</ResourceDictionary>

You can create separate resource dictionaries for your controls and put them in the same folder as your code’s control. Make sure you set the build action for the resource dictionary to ‘Resource’.

A drawback of this solution is that you need to specify the assembly name for each resource dictionary that you want to merge. This is a flaw in WPF when using merged dictionaries in Generic.xaml.

TabControl’s ContentTemplate cannot be changed dynamically

TabControl bug exampleI recently used a TabControl and required a different ContentTemplate per item, so I used datatriggers to change the ContentTemplate based on the current selected page. In theory this should work fine, but I found that changes to the ContentTemplate are not effectuated.

How to reproduce?
Use the following XAML code to illustrate the problem. The property trigger based on the ‘IsMouseOver’ property changes the content template, when you hover over it. This should make the text to be displayed in bold, but it doesn’t show until you change the page.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Page.Resources>

    <DataTemplate x:Key="TabHeaderTemplate">
      <TextBlock Text="{Binding XPath=@header}"/>
    </DataTemplate>

    <DataTemplate x:Key="TabContent1">
      <TextBlock FontWeight="Normal" Text="{Binding XPath=@header}"/>
    </DataTemplate>

    <DataTemplate x:Key="TabContent2">
      <TextBlock FontWeight="Bold" Text="{Binding XPath=@header}"/>
    </DataTemplate>

    <Style x:Key="DynamicTabControl" TargetType="TabControl">
      <Setter Property="ContentTemplate" Value="{StaticResource TabContent1}"/>
      <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="ContentTemplate" Value="{StaticResource TabContent2}"/>
        </Trigger>
      </Style.Triggers>
    </Style>

    <XmlDataProvider x:Key="tabPages" XPath="/pages">
      <x:XData>
        <pages xmlns="">
          <page header="Page 1"/>
          <page header="Page 2"/>
          <page header="Page 3"/>
        </pages>
      </x:XData>
    </XmlDataProvider>

  </Page.Resources>

  <TabControl ItemsSource="{Binding Source={StaticResource tabPages}, XPath=*}"
              ItemTemplate="{StaticResource TabHeaderTemplate}"
              Style="{StaticResource DynamicTabControl}"/>

</Page>

What’s the cause?
I was wondering what was happening, so I started my favorite .NET Reflector tool and found out that the ContentTemplate is set in code instead of a binding. The following piece of code takes care of setting the content template and horizontal/vertical alignment (which will probably suffer from the same problem):

private void TabControl.UpdateSelectedContent()
{
  // Check if a tab is selected
  if (base.SelectedIndex < 0)
  {
    this.SelectedContent = null;
    this.SelectedContentTemplate = null;
    this.SelectedContentTemplateSelector = null;
    this.SelectedContentStringFormat = null;
  }
  else
  {
    // Obtain the selected tab item
    TabItem selectedTabItem = this.GetSelectedTabItem();
    if (selectedTabItem != null)
    {
      // Some keyboard stuff removed here...

      // Set the content
      this.SelectedContent = selectedTabItem.Content;

      // Obtain the content presenter for the selected item
      ContentPresenter selectedContentPresenter = this.SelectedContentPresenter;
      if (selectedContentPresenter != null)
      {
        // Set horizontal/vertical alignment
        selectedContentPresenter.HorizontalAlignment = selectedTabItem.HorizontalContentAlignment;
        selectedContentPresenter.VerticalAlignment = selectedTabItem.VerticalContentAlignment;
      }

      // Check if the selected tab item defines the content template
      if ((selectedTabItem.ContentTemplate != null) ||
          (selectedTabItem.ContentTemplateSelector != null) ||
          (selectedTabItem.ContentStringFormat != null))
      {
        // Use the content settings from the tab item
        this.SelectedContentTemplate = selectedTabItem.ContentTemplate;
        this.SelectedContentTemplateSelector = selectedTabItem.ContentTemplateSelector;
        this.SelectedContentStringFormat = selectedTabItem.ContentStringFormat;
      }
      else
      {
        // Use the content settings from the tab control
        this.SelectedContentTemplate = this.ContentTemplate;
        this.SelectedContentTemplateSelector = this.ContentTemplateSelector;
        this.SelectedContentStringFormat = this.ContentStringFormat;
      }
    }
  }
}

As you can see, the ContentTemplate is set directly, so updating it after this method has completed doesn’t do anything until the method is invoked again. This method is a private method that is called when one of the following events happen:

  • A new template is applied to the TabControl (TabControl.OnApplyTemplate).
  • Another tab page is selected (TabControl.OnSelectionChanged).
  • TabControl’s ItemGenerator status is updated (TabControl.OnGeneratorStatusChanged).

Changes made to the TabControl’s ContentTemplate will therefore only be propagated, when one of these events occur. If you change the ContentTemplate afterwards, then you are out of luck.

How to fix it?
The best way to solve this issue is to use binding, because the binding mechanism will ensure that all properties are updated properly. Unfortunately, you cannot do this, because some of the required properties are read-only and cannot be modified from your code.

The only way to fix it is to override the property metadata for these dependency properties and make sure that the TabControl.UpdateSelectedContent() method is invoked when the dependency property is changed. You cannot call this method directly, but you can call it by calling the public TabControl.OnApplyTemplate() method. The same fix should be made for the TabItem, because if the TabItem has its own template, then this template is used.

I have created a sample application that includes the MyTabControl and MyTabItem classes that contain this workaround.
Tab Control bug example

Beware of routed events

WPF introduces the concept of routed events. There are different routing strategies, but the most commonly used strategy is the bubbling strategy. With the bubbling strategy, the event handlers on the event source are invoked. The routed event then routes to successive parent elements until reaching the element tree root or when a handler sets the Handled property.

Always make sure that you set the Handled property, when you handle a routed event. It’s easy to forget, but the framework walks up the tree to find another handler. This has a performance penalty, but it might have unwanted side-effects that are even worse.

When you use controls that can be nested, then you should take extra care when handling routed events. Suppose we have the following code:

<Expander x:Name="Expander1" Header="Expander 1" Collapsed="OnExpander1Collapsed">
  <Expander x:Name="Expander2" Header="Expander 2">
    <TextBlock Text="Routed event test application."/>
  </Expander>
</Expander>

And we implement the Collapsed handler like this:

private void OnExpander1Collapsed(object sender, RoutedEventArgs e)
{
   MessageBox.Show("Expander 1 is collapsed.");
   e.Handled = true;
}

When you collapse Expander 1, then the message is shown. But guess what happens if you collapse the inner expander? The inner Expander raises the Collapsed event and the framework will search for an appropriate handler. The Collapsed event is defined as a bubbling event, so it will start at the source (the inner expander) and will go up the visual tree. When it reaches the outer expander, then it will call the event handler.

You can solve the problem by adding an event handler for the inner expander and set its Handled property. It works in this example, but it won’t if a third-party control raised the event. The only way to solve this problem is to check the source of the event, so the event handler should read:

private void OnExpander1Collapsed(object sender, RoutedEventArgs e)
{
  if (e.OriginalSource == this.Expander1)
  {
    MessageBox.Show("Expander 1 is collapsed.");
    e.Handled = true;
  }
}

In this example the problem is clearly visible. But things can get really nasty in more complex scenarios. Suppose you use an expander control in your code and some changes the template of another control so it uses an expander too. If this control is used within your expander, then things might get pretty nasty if you handle the Expanded and/or Collapsed events.

So make sure you check the source of the event for routed events. The disadvantage is that you have to name your control, which adds additional fields to your class. If the expander is inside a data template, then checking the name is a little bit more difficult, but not impossible:

private void OnExpander1Collapsed(object sender, RoutedEventArgs e)
{
  var originalSource = e.OriginalSource as Framework;
  if ((originalSource != null) && (originalSource.Name == "Expander1"))
  {
    MessageBox.Show("Expander 1 is collapsed.");
    e.Handled = true;
  }
}

Windows Phone 7 SDK

This Windows Phone 7 SDK has been released this week and I must say that I am impressed and disappointed at the same time. Let’s start with the positive things:

  • WP7 applications use Silverlight 4, which is a great and elegant programming model.
  • A WP7 simulator is included which works fast and easy.
  • The SDK fully integrates in VS2010.NET

The negatives:

  • It uses a subset of Silverlight 4, which lacks a lot of functionality (at this moment?). Even a simple DockPanel is not available (although this is easy to implement).
  • No local database support. There are some open-source solutions, but I would rather use something like SQL-Server for Mobile.

The programming model is much better than Apple’s Cocoa Touch framework. Silverlight is much more elegant compared to the ancient Objective-C stuff that Cocoa Touch uses. The drawback is that Apple’s system is more mature. You can access a standard database and it ships which better controls than WP7 does. Maybe things get better before WP7 ships, but there is still a lot of work to do for Microsoft.