Archive for October, 2007

Continuing Quest for "Star"-dom

Thursday, October 25th, 2007

I just noticed that it’s been exactly two months since I joined the MSDN forums, so here’s my two-month update on my quest for 5 gold stars…

MSDN Profile

At the moment, I have exactly 3500 points, which puts me solidly in the middle of 3 stars.  I’m not quite half way to my 4th star (7500 points).  And at this rate, I should achieve my 5th star (15000 points) about 6 months from now.  Then I will finally be able to retire into obscurity (unless people start haphazardly marking all of my posts as helpful, in which case I could retire sooner)!  😉 

It’s quite clever of Microsoft to invent this little rating system that takes full advantage of the obsessive-compulsive nature of geeks to defend their geekdom.

ItemsControl: 'B' is for Bet You Can't Find Them All!

Monday, October 22nd, 2007

This is Part B in my “ItemsControl: A to Z” series.  Part A served mostly as an introduction to the ItemsControl class (one of the most abundant classes in many WPF applications).  We looked at several common ItemsControl samples involving controls like ListBox, ListView, TreeView, etc.  In this post, we will build on that introduction in what I hope will be a fun challenge and a good learning experience. 

What’s your ICIQ?

You will shortly be presented with a small, interactive quiz called “The ItemsControl Intelligence Quotient (ICIQ) Test”.  The purpose of “The ICIQ Test” is to see how well you can recognize different ItemsControl instances in a real WPF application.  You will be shown a screenshot of a WPF application that is used internally by the Microsoft Dynamics Team to build and visualize customer models.  (Special thanks to Microsoft for providing me with the image!)

Full Disclosure:  It’s Rigged!

Despite the name, “The ICIQ Test” does not really measure intelligence… rather, it measures your observational and deductive reasoning skills regarding the usage of items controls.  And yes, this test is completely unfair!  Even for the seasoned WPF developer, there will be some visuals in the snapshot that could go either way.  You’ve been warned!

It’s Intended to be a Learning Experience

Ultimately, I hope you will approach this as a learning experience.  (Well, unless you happen to get a really high score, in which case you should run around the office gloating about your extremely high ICIQ and immediately demand a raise from your boss!) 

This test should help reinforce some core concepts regarding the lookless nature of WPF controls and the power of templating to present native controls in ways that are visually meaningful.

When you complete the test, you will have an opportunity to further explore the different ItemsControl examples in the application, as shown below: 

Learning Tips

If you are new to WPF, some of the terms like “items host” and “item container” may not make sense yet.  All of these concepts will be covered in detail as this series progresses. 

“Enough already!  Let me take the test!”

Go for it!  Here’s your official link to “The ICIQ Test“.  I look forward to hearing how unfair it was!!  😉

And don’t forget to come back for the next installment in this series:  ‘C’ is for Collection.

Cheers,
Dr. WPF

ToolTip Positioning

Tuesday, October 16th, 2007

Hi Dr. WPF,

I have a Window which is filled with multiple images shown on it side-by-side and I have a need to show a popup window when somebody hover overs an image element. Please note that it is not really a new window but somewhat like a tooltip (but not exactly that). The popup will contain a bigger version of the image they hovered over originally and if they move their mouse over another image, the popup will contain that image at that time and will move over the image the user last hovered over.

Can you please help me with this? I have tried playing with the “Popup” element and the “Tooltip” element but have not found a workable solution yet – I was not able to place the tooltip at the location I wanted (it always appeared a little below the mouse cursor).

Thanks,
Paras
 

 

Hi Paras,

I couldn’t resist the opportunity to answer your question online, since the sample I came up with fits so nicely with the ItemsControl series I just started, ItemsControl:  A to Z.  (Yeah, I know thats not the point of your question, but still…)

Here are the key properties to use when you are positioning a Popup:

  • Placement
  • PlacementTarget
  • PlacementRectangle
  • VerticalOffset
  • HorizontalOffset

These are explained fairly well in this article in the docs.  There are also a couple of application samples in the docs you can download here and here.  But since you just want something quick…

Below you will find a very simple sample that implements the scenario you describe above using a ToolTip.  You should be able to paste the XAML directly into XamlPad.  Note that the popups may be slow since the images are being pulled across the web.  For a more performant version, you can update the strings in the Items collection to point at local files on your hard drive. 

This example uses the Placement property on the ToolTip with a value of “Bottom” combined with the HorizontalOffset and VerticalOffset properties to further displace the ToolTip.  You can play with the values in XamlPad until you find what you like.


<Grid xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:sys="clr-namespace:System;assembly=mscorlib">
 
  <Grid.Resources>

    <ControlTemplate x:Key="ICWithScrollingWrapPanel"
        TargetType="{x:Type ItemsControl}">
      <Border Background="{TemplateBinding Background}"
          BorderBrush="{TemplateBinding BorderBrush}"
          BorderThickness="{TemplateBinding BorderThickness}">
        <ScrollViewer Margin="{TemplateBinding Padding}">
          <WrapPanel IsItemsHost="True" />
        </ScrollViewer>
      </Border>
    </ControlTemplate>

    <ToolTip x:Key="ImageToolTip" Placement="Bottom"
        HorizontalOffset="20" VerticalOffset="5">
      <Grid Background="Gray">
        <Image Source="{Binding}" />
      </Grid>
    </ToolTip>

    <DataTemplate x:Key="ImageTemplate">
      <Image Width="100" MaxHeight="100" Margin="5"
          ToolTip="{StaticResource ImageToolTip}"
          Source="{Binding}" />
    </DataTemplate>

  </Grid.Resources>

  <ItemsControl Width="355" Height="200" Background="LightGray"
      BorderBrush="Black" BorderThickness="1" Padding="2"
      Template="{StaticResource ICWithScrollingWrapPanel}"
      ItemTemplate="{StaticResource ImageTemplate}">
    <sys:String>http://www.microsoft.com/presspass/images/gallery/campus/bldg10_flags_web.jpg</sys:String>
    <sys:String>http://techfreep.com/images/googleplex.jpg</sys:String>
    <sys:String>http://www.sfgate.com/c/pictures/2006/12/24/bu_earns_yahoo_ny.jpg</sys:String>
    <sys:String>http://img.groundspeak.com/waymarking/b696fde2-62b8-426c-81dd-4e3ae6836402.jpg</sys:String>
    <sys:String>http://www.svdaily.com/applehq.jpg</sys:String>
    <sys:String>http://www.nextcomputers.org/NeXTfiles/Images/History/NeXT_Buildings/redwood02.jpg</sys:String>
    <sys:String>http://explorer.altopix.com/uploads/hz166e.jpg</sys:String>
    <sys:String>http://www.ti.com/corp/graphics/press/image/on_line/co1772.jpg</sys:String>
    <sys:String>http://www.freefotoexchange.netsons.org/data/510/61121758627-1.jpg</sys:String>
  </ItemsControl>

</Grid>

 
Hope this helps!

Best regards,
Dr. WPF

ItemsControl: 'A' is for Abundance

Monday, October 15th, 2007

This is the first post in a series I’m calling, “ItemsControl: A to Z”.

I’ve received quite a few questions lately that were either directly or indirectly related to the ItemsControl class. It’s noteworthy that often, the questioner did not even realize they were asking an ItemsControl question.

So it occurs to me that there may be a general need for better information about this class, including its usages, nuances, idiosyncrasies, as well as all the WPF goodness that can be had through styling and templating an ItemsControl and binding a collection to it.

(And let me just say up front that it’s highly unlikely I’ll make it all the way to Z without skipping a few letters. J)

But first things first… I suppose we should start with the basics.

What is an ItemsControl?

Quite simply, an ItemsControl is a control that presents a collection of items.

The ItemsControl is one of the most abundant controls in the user interface of just about any WPF application. It is the base class of every native WPF control that presents a collection of items, including but not limited to the following:

 

ComboBox
<ComboBox SelectedIndex="0">
  <ComboBoxItem>Item 1</ComboBoxItem>
  <ComboBoxItem>Item 2</ComboBoxItem>
  <ComboBoxItem>Item 3</ComboBoxItem>
</ComboBox>
 
ContextMenu
Menu
MenuItem
<ContextMenu>
  <MenuItem Header="New"/>
  <MenuItem Header="Open"/>
  <Separator/>
  <MenuItem Header="Submenu">
    <MenuItem Header="Submenu Item 1"/>
    <MenuItem Header="Submenu Item 2"/>
  </MenuItem>
</ContextMenu>
 
ListBox
<ListBox SelectedIndex="0" Width="100">
  <ListBoxItem>Item 1</ListBoxItem>
  <ListBoxItem>Item 2</ListBoxItem>
  <ListBoxItem>Item 3</ListBoxItem>
  <ListBoxItem>Item 4</ListBoxItem>
  <ListBoxItem>Item 5</ListBoxItem>
</ListBox>
 
ListView
<ListView SelectedIndex="0" Height="110"
    ItemsSource="{StaticResource Characters}">
  <ListView.View>
    <GridView>
      <GridViewColumn Width="100"
        DisplayMemberBinding="{Binding Last}"
        Header="Last Name" />
      <GridViewColumn Width="100"
        DisplayMemberBinding="{Binding First}"
        Header="First Name" />
      <GridViewColumn Width="60"
        DisplayMemberBinding="{Binding Gender}"
        Header="Gender" />
    </GridView>
  </ListView.View>
</ListView>
 
TabControl
<TabControl Width="150" Height="100">
  <TabItem Header="One">
    <TextBlock>Hello World</TextBlock>
  </TabItem>
  <TabItem Header="Two" />
  <TabItem Header="Three" />
</TabControl>
 
ToolBar
<ToolBar Margin="2">
  <Button Command="ApplicationCommands.Open"
      Height="40" Width="40"
      Background="{StaticResource OpenIcon}" />
  <Button Command="ApplicationCommands.Save"
      Height="40" Width="40"
      Background="{StaticResource SaveIcon}" />
</ToolBar>
 
TreeView
TreeViewItem
<TreeView Width="150" Height="100"
    ItemsSource="{StaticResource Characters}">
  <TreeView.Resources>
    <HierarchicalDataTemplate
        DataType="{x:Type src:Character}"
        ItemsSource ="{Binding Fact}">
      <TextBlock Text="{Binding Name}" />
    </HierarchicalDataTemplate>
    <DataTemplate DataType="{x:Type src:Fact}">
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Name}" />
        <TextBlock Text=": " />
        <TextBlock Text="{Binding Value}" />
      </StackPanel>
    </DataTemplate>
  </TreeView.Resources>
</TreeView>

A Control in its Own Right

The controls listed above are most often used because of the additional features they provide on top of the base ItemsControl class. However, it should also be noted that an ItemsControl may be instantiated and used directly, as shown in the following example:

<Grid xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition />
  </Grid.RowDefinitions>
  <ItemsControl VerticalAlignment="Top">
    <ItemsControl.ItemTemplate>
      <DataTemplate>
        <Button Command="{Binding}" Content="{Binding}"
          CommandTarget="{Binding ElementName=EditRegion}" />
      </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal" />
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <x:Static Member="ApplicationCommands.Cut" />
    <x:Static Member="ApplicationCommands.Copy" />
    <x:Static Member="ApplicationCommands.Paste" />
  </ItemsControl>
  <TextBox Name="EditRegion" Grid.Row="1" />
</Grid>

This markup creates what you might call a poor man’s toolbar. (No, it’s not a very likely real-world scenario.) In future posts, we will explore reasons why you might choose to use an ItemsControl directly, rather than, say, a ListBox.

Is a Panel an ItemsControl?

No. The logical children of a panel are UIElements, whereas the logical children of an ItemsControl (its Items) can be any CLR objects.

Sidebar: So what is a panel? The main role of a panel is to provide layout support for its children. Although a panel does maintain a collection of child elements, it is not technically a WPF “control”… That is, it does not derive from the Control base class and it does not support the WPF notion of templating. Instead, it is a single element with a single purpose… namely, to size and position (a.k.a., measure and arrange) its children.

Why should I care about the ItemsControl class?

Since it’s such an abundant control, it will pay dividends to take time now to understand the basic principles that apply to the ItemsControl class and its descendants. Once you understand these concepts as they pertain to one ItemsControl variant, perhaps a ListBox, it will be very easy to apply that same knowledge to other variants.

And suppose you should someday stumble upon a declaration like this:

<dw:Graph ItemsSource="{Binding Source={StaticResource OrgChartItems}}"
    ItemContainerStyle="{StaticResource NodeStyle}"
    ItemTemplate="{StaticResource EmployeeTemplate}"
    ItemsPanel="{StaticResource TreeGraphPanelTemplate}" />

Armed with your existing knowledge, you won’t panic in the least. You will simply recognize that this Graph object is a custom ItemsControl and you will immediately understand how to use the majority of its features.

What will be covered?

In future posts in this series, I hope to cover each of the topics below in some detail. I’m sure this is not an exhaustive list, but it should give you a general feel for the direction of the series.

  • The Item Collection: Items vs. ItemsSource
  • Recognizing when to use an ItemsControl
  • Item Templates
  • Item Containers
  • Item Container Generation
  • The Items Host (or ItemsPanel)
  • Styling and Templating an ItemsControl
  • Traversing Container and Template Trees
  • The HeaderedItemsControl
  • Styling and Templating a Headered ItemsControl
  • Building a Custom ItemsControl and Item Containers
  • UI Virtualization

Please let me know what other topics you’d like me to add to the list. And please stay tuned for the next topic in this series… “B is for Bet You Can’t Find Them All!”

Enhancing Developer/Designer Productivity

Monday, October 8th, 2007

“Joe” added the following comment to my earlier post on WPF project structure:

I would be interested to know how developers tackle the Blend issue. I’ve hit problems when most of the visuals are embedded in Data Templates and you only see the final product when real data is populated into the ItemsControls. Are developer teams using canned data just to edit the visuals?

The answer to that question for most of the projects I’ve worked on is definitely “yes”.  Designers are most effective when they can edit templates directly.  To do this in Blend, you often have to simulate the real data by using fake data.

Laurent Bugnion just posted a nice screencast on a very structured approach to enhancing designer/developer productivity in WPF.  This approach is built around the concept that there are three distinct personas involved in the development process:  designer, developer, and integrator (the ever-elusive “devigner” who understands both worlds and can work in the middle to integrate the code and the design).

And in this earlier blog post, Laurent provides an article demonstrating how one might provide “canned data” in design mode to accomodate the editing of templates in Blend.

Managing Application Resources when WPF is Hosted

Friday, October 5th, 2007

Dear Dr. WPF,

We are running into some issues around application level resources when we attempt to put WPF task pane UI within Office. The primary issue is that the runtime host is not WPF in these cases which means that Application.Current.Resources is not available. That in turn affects how static resource references are handled in the xaml and how FindResource() works in code.

We’re curious if you have any viable solutions or experience with this type of situation. I’m guessing that in addition to Office/VSTO that Winforms hosted interop would have similar issues.

Thanks,
Brian


Dear Brian,

Managing application-level resources in an interop scenario like yours, where WPF is being hosted within another technology like Win32 or Windows Forms, definitely requires more work on the part of the developer. In this post I’ll describe a number of approaches that you might take and you can decide which is the most appropriate for your scenario.

Brief Intro to Resources and Resource Resolution

For those who may be new to WPF (or who may just want a refresher), this section contains a brief introduction to resources and resource resolution. Feel free to skip ahead if you’re already familiar with these concepts.

Each framework element (which means any descendant of FrameworkElement or FrameworkContentElement) has a Resources collection. This collection is of type ResourceDictionary. The ResourceDictionary type truly represents a CLR Dictionary in which each value (or resource) has a unique key.

The fact that every framework element has its own Resources collection allows resources to be defined at any level in the element tree.

<Grid Margin="20" x:Name="RootGrid">
  <Grid.Resources>
    <Storyboard x:Key="FadeOutGlassStoryboard" TargetProperty="Opacity">
      <DoubleAnimation To="0" Duration="0:0:0.5" />
    </Storyboard>
  </Grid.Resources>
  . . .
  <StackPanel>
    <StackPanel.Resources>
      <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
              <ContentPresenter
                  ContentTemplate="{TemplateBinding ContentTemplate}"
                  Content="{TemplateBinding Content}" />
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
    </StackPanel.Resources>
    . . .
  </StackPanel>
</Grid>

 

In addition, resources can be defined at the application level within a markup file called an application definition file:

<Application x:Class="WindowsApplication1.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1">
  <Application.Resources>
    <ResourceDictionary>
      <Style x:Key="{x:Type GridSplitter}" TargetType="{x:Type GridSplitter}">
        <Setter Property="IsTabStop" Value="False" />
      </Style>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Resources\ConverterResourceDictionary.xaml"/>
        <ResourceDictionary Source="Resources\LogoDictionary.xaml"/>
        <ResourceDictionary Source="Resources\ColorsResourceDictionary.xaml"/>
        <ResourceDictionary Source="Resources\IconResourceDictionary.xaml"/>
        <ResourceDictionary Source="Resources\SimpleStyles.xaml"/>
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>
</Application>

And finally, resources can be defined at the theme level. In addition to the built-in Windows themes, control libraries might define their own theme-level resources.

So there are several levels at which resources may be defined. Now let’s look at how you use (a.k.a., reference) resources.

In markup, a resource reference can be either static or dynamic. There are slightly different rules that apply to each:

  • A static reference is applied to a property in XAML by using the {StaticResource xxx} markup extension and a dynamic reference is applied via the {DynamicResource yyy} extension, where xxx and yyy represent the respective resource keys.
  • A static reference can be used to set any CLR property, whereas a dynamic reference can only be used to set dependency properties on framework elements or freezables or to set the Value property of Setter objects in styles.
  • Static resource references are resolved at parse time (for the most part), whereas dynamic references are resolved at run time. This means a static reference can only be used if the resource has been parsed before the reference, whereas a dynamic reference can be used as a forward reference for a resource that is defined later.

The process of resource resolution begins with the referencing element. First, the Resources collection of the referencing element is checked. If a dynamic reference was used and the element has a Template and/or Style, the Resources collections of the Template and Style are also checked. If the resource was not found, resource resolution then continues up the element tree by searching the Resources collections of each parent until the resource is found.

Resource resolution always favors the logical tree. (If an element does not have a logical parent, resolution will begin through the visual tree until an ancestor is found in the logical tree and it will then continue up the logical tree.) If the root of the logical tree is reached and the resource has not been resolved, the application-level resource dictionary will be searched. If still unresolved and a dynamic resource reference was used (or a static reference was deferred), then the theme resources will be checked.

Resources can also be retrieved in code by using the FindResource() method on a framework element. The resolution process is very much the same as with dynamic references.

Resource Considerations for Custom Controls

There are special considerations around resources when writing custom control libraries. My focus in this post is purely on managing application-level resources in a hosted interop scenario. For anyone writing a control library, I would recommend that you check out the following post in the WPF SDK blog:

Using Shared Resources in a Controls Library.

Application-Level Resources in a WPF Application

When building a typical WPF application, the MSBuild project file contains a project element named ApplicationDefinition. This element identifies a XAML file whose root descends from the Application class. So for a C# project, the Application class files would appear as follows in the .csproj file.

<ApplicationDefinition Include=”App.xaml” />
<Compile Include=”App.xaml.cs”>
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>

MSBuild now knows that this class represents the entry point for the WPF application, so it auto-generates a file named App.g.cs that contains an entry point, as follows:

[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static void Main() {
    WindowsApplication1.App app = new WindowsApplication1.App();
    app.InitializeComponent();
    app.Run();
}

This is the code that instantiates the Application class in a typical WPF application.

As mentioned earlier, the Application class contains a Resources property which identifies the ResourceDictionary where application-level resources reside. A typical ApplicationDefinition file was presented in the introduction section above.

Note that there can be individual resources in the Application’s Resources collection as well as additional merged resource dictionaries. All such resources are available at the application level, and thus, can be referenced freely throughout the application. This provides an elegant mechanism for theming the application, as well as for sharing common resources among different pages, windows, user controls, etc.

Providing Application-Level Resources when WPF is Hosted

When WPF is hosted inside a managed application framework like Windows Forms or in an unmanaged framework like MFC or pure Win32, this elegance provided by application-level resources is lost because WPF’s Application object does not even get created. (Recall that it is the auto-generated code that actually creates the Application instance.) As such, resource resolution occurs only within the element tree and at the theme level.

The good news is that there are several ways to effectively bring back the benefits of application-level resources in these hosted interop scenarios…

Create an Application Instance and Add Resources in Code

The most obvious approach is to simply create an instance of the Application class. Since the Application class is a singleton, you can simply instantiate an instance of the class and then you have access to it throughout your app. Of course, at that point, its Resources collection is empty, so you will probably want to add some resources. Since it is more convenient to declare resources in markup, I typically define my resources in a ResourceDictionary and then merge them into the Resources collection in my Application object.

Below is a very simple function that will create the Application object if it does not exist and then load some resources:

public static void EnsureApplicationResources()
{
    if (Application.Current == null)
    {
        // create the Application object
        new Application();

        // merge in your application resources
        Application.Current.Resources.MergedDictionaries.Add(
            Application.LoadComponent(
                new Uri("MyLibrary;component/Resources/MyResourceDictionary.xaml",
                UriKind.Relative)) as ResourceDictionary);
    }
}

Now you just need to make sure that you call this function prior to parsing any XAML files that contain static resource references to application-level resources. To do this, simply add a call to the above function in the constructor of your markup-based classes before any call to InitializeComponent():

public Page1()
{
    EnsureApplicationResources();
    InitializeComponent();
}

Voîla! You now have application-level resource resolution in your hosted scenario.

There are a couple of things worth pointing out here. First, in this scenario, we are only using the Application object for resource resolution. You would not want to call the Application’s Run() method in the hosted scenario, since that would start a WPF dispatcher. In our scenario, the hosting technology is responsible for dispatching Windows messages. (The exception might be if the host was a Win32 console app, in which case you would need to supply a message pump for WPF.)

Another thing to keep in mind is that the Application singleton will remain alive for the remainder of the process lifetime unless you take steps to release it. If your scenario only calls for WPF to be used for a finite period of time during application execution, you should call the Application’s Shutdown() method when you no longer need it. In a non-hosted WPF application, this would actually shut down the application by shutting down the dispatcher. In our hosted scenario, it will simply release the rooted reference to the singleton. After calling Shutdown(), the static Application.Current property will once again return null. At this point, the object should be available for garbage collection.

Define the Application Class in XAML and Create It on the Fly

The above approach is nifty, but it requires us to do the work of adding and merging resources in code. This is great if you want dynamic control over exactly which resources are added. But if your scenario always calls for the same application-level resources, wouldn’t it be easier to just define those in markup the same way you would for a native WPF application?

Good news… You can! You just need to make a couple of small changes to the MSBuild project file and the code-behind for your Application class.

First, we do not want MSBuild to generate an application entry point for our Application class. So instead of declaring the App.xaml file as an ApplicationDefinition element in the project file, we need to declare it as a Page element:

<Page Include="App.xaml" />
<Compile Include="App.xaml.cs">
  <DependentUpon>App.xaml</DependentUpon>
  <SubType>Code</SubType>
</Compile>

Next, we need to make sure that our App.xaml markup is parsed. Typically, this is done as part of the entry point function (which we just eliminated). Instead, we can simply define a constructor for the Application class and call InitializeComponent directly:

public App()
{
    InitializeComponent();
}

Now all our resources and merged dictionaries can be declared in App.xaml and our static function to load the Application instance can be as simple as this:

public static void EnsureApplicationResources()
{
    if (Application.Current == null)
    {
        // create the Application object
        new App();
    }
}

Manage a Collection of Resource Dictionaries in Code and Merge them at the Element Level

The final approach I’ll discuss for managing application resources in a hosted scenario involves programmatically managing a collection of resource dictionaries. In this scenario, we do not leverage an Application object at all. Instead, we dynamically load each ResourceDictionary at runtime and selectively merge it into pages or windows or specific elements, as necessary.

Clearly, this puts more responsibility on the developer for ensuring that the proper resources are merged at the proper locations. But it has benefits too, such as better scoping of resources and not having to track the lifetime of the Application object.

When using this approach, the trick to ensuring that application resources are truly shared across element trees is to only create a single instance of each resource dictionary. This can easily be accommodated by leveraging a static dictionary of dictionaries:

private static Dictionary<string, ResourceDictionary>
    _resourceDictionaries = new Dictionary<string, ResourceDictionary>();

Now each dictionary can be referred to using a simple name, such as “ApplicationBrushes”. A static utility function can be used to retrieve the resource dictionary by name. If the dictionary is not loaded, the function can automatically load it:

public static ResourceDictionary GetResourceDictionary(string dictionaryName)
{
    if (!_resourceDictionaries.ContainsKey(dictionaryName))
    {
        _resourceDictionaries[dictionaryName] = Application.LoadComponent(
            new Uri("MyLibrary;component/Resources/" + dictionaryName + ".xaml",
            UriKind.Relative)) as ResourceDictionary;
    }
    return _resourceDictionaries[dictionaryName];
}

And to make this solution play nicely in the WPF world, we should allow dictionaries to be merged declaratively in our markup files. One way to do this is to leverage an attached property. Suppose we define a static class called SharedResources and in that class we define a string property called MergedDictionaries. This would allow us to merge in shared resource dictionaries to the Resources collection of any framework element, by simply doing this:

<Grid dw:SharedResources.MergedDictionaries="ApplicationBrushes;ButtonStyles">
    . . .
</Grid>

As you can see, my MergedDictionaries property allows for a semicolon-delimited list of resource dictionaries that should be merged into the Resources collection of the Grid.

The only thing left to do now is actually implement the SharedResources class and the MergedDictionaries attached property. Here is that class in its entirety with a few bonus refinements:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Reflection;

namespace DrWPF.Windows
{
    public static class SharedResources
    {
        #region MergedDictionaries

        public static readonly DependencyProperty MergedDictionariesProperty =
            DependencyProperty.RegisterAttached("MergedDictionaries",
                typeof(string), typeof(SharedResources),
                new FrameworkPropertyMetadata((string)null,
                    new PropertyChangedCallback(OnMergedDictionariesChanged)));

        public static string GetMergedDictionaries(DependencyObject d)
        {
            return (string)d.GetValue(MergedDictionariesProperty);
        }

        public static void SetMergedDictionaries(DependencyObject d, string value)
        {
            d.SetValue(MergedDictionariesProperty, value);
        }

        private static void OnMergedDictionariesChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.NewValue as string))
            {
                foreach (string dictionaryName in (e.NewValue as string).Split(';'))
                {
                    ResourceDictionary dictionary =
                        GetResourceDictionary(dictionaryName);
                    if (dictionary != null)
                    {
                        if (d is FrameworkElement)
                        {
                            (d as FrameworkElement).Resources
                                .MergedDictionaries.Add(dictionary);
                        }
                        else if (d is FrameworkContentElement)
                        {
                            (d as FrameworkContentElement).Resources
                                .MergedDictionaries.Add(dictionary);
                        }
                    }
                }
            }
        }

        #endregion

        private static ResourceDictionary GetResourceDictionary(string dictionaryName)
        {
            ResourceDictionary result = null;
            if (_sharedDictionaries.ContainsKey(dictionaryName))
            {
                result = _sharedDictionaries[dictionaryName].Target;
            }
            if (result == null)
            {
                string assemblyName = System.IO.Path.GetFileNameWithoutExtension(
                    Assembly.GetExecutingAssembly().ManifestModule.Name);
                result = Application.LoadComponent(new Uri(assemblyName
                    + ";component/Resources/" + dictionaryName + ".xaml",
                    UriKind.Relative)) as ResourceDictionary;
                _sharedDictionaries[dictionaryName] = new WeakReference(result);
            }
            return result;
        }

        private static Dictionary<string, WeakReference> _sharedDictionaries
            = new Dictionary<string, WeakReference>();
    }
}

Notice that in this implementation, instead of keeping a dictionary of dictionaries, I’m keeping a dictionary of weak references to dictionaries. This ensures that my static class does not keep any resource dictionary in memory when it is no longer in use. (The class could certainly be augmented to provide a mechanism to lock a resource dictionary in memory for times when you want to persist resources across application lifetime. In the name of simplicity, I’ll leave that as an exercise for the reader.)

So there you have a few options for dealing with application-level resources while running hosted. Hope it helps!

Best regards,
Dr. WPF

A WPF Project Needs Structure

Monday, October 1st, 2007

Dear Dr. WPF,

I am about to begin a rather large WPF project.  I’ve worked on plenty of development efforts involving Windows Forms projects and even a few Win32 projects, but this will be my first foray into WPF.  Can you give me general guidance on how to best structure a Visual Studio solution that is targeting WPF?

Sincerely,
Sacha V. 


Hi Sacha,

When people are first getting started with WPF, they often feel more than just a little intimidated.  The platform is so big and something as basic as project structure may seem overwhelming.  If you find yourself in this position, my advice is to charge ahead blindly!  Don’t let the unknowns prevent you from making immediate progress. 

I’m happy to share some things I’ve learned on this subject…

Just to be clear, I’m not referring to application architecture in this post.  (However, I’m more than willing to expound on that topic too.  But if you’re just starting, you would probably find such a discussion mind numbing at this point.  If you really care, let’s just say that I tend to follow an architecture similar to the model-view-viewmodel approach described by John Gossman.  I never had a name for it until he blogged about it, and I still don’t have a name for it.  I think his chosen term suffers from the same branding problems as the WPF platform itself, so I refuse to call it m-v-vm. ) 

In this discussion, I’m talking only about how you structure and manage the projects, files, resources, etc, within your Visual Studio/Expression Blend solution.  I believe this is what you are asking about, correct?

The good news is that it’s fairly simple to change your structure along the way as long as you regularly revisit the topic and keep things heading in the right general direction.

Is there a right way to structure a WPF solution?

Yes, absolutely.

What is the right way to structure a WPF solution?

There is not one.

Huh?

Okay, before you accuse me of contradicting myself, let me just clarify that this is an exercise in semantics and these two questions are actually quite different.  (If everyone could please pull out their high school grammar books, we’ll continue…)  In the first question, the indefinite articlea” is used (“a right way”) so the question is asking if there is at least one right way.  In the second question, the definite articlethe” is used (“the right way”) to effectively ask for the one and only right way.

My whole point here is that you shouldn’t get caught up thinking there is only one correct way to structure your solution.  There is definitely not a one-size-fits-all structure for WPF solutions.  The general rule is that the project, itself, should determine the project structure.  WPF is no different than any of the previous platforms you’ve targeted in this respect.

Having said that, I definitely think there are some patterns that can be followed to make WPF solutions more manageable, sensible, and approachable for the developers and designers working on the project. 

Use Project Folders

This one goes without saying… but I’m saying it anyway.  Good project structure begins by organizing project files in a meaningful way.  Unless we’re talking about an extremely simple project with one or two windows or navigation pages, you should be leveraging folders within your project to keep files logically organized.  My projects typically have at least a rudimentary set of root folders, as shown in the Solution Explorer image to the right.

Organize by Resource Type

WPF applications tend to have many different types of resources.  For large applications, it makes sense to use separate subfolders for common types of resources.  In most of my projects, you will at least find a root project folder named Resources.  Within there, you are likely to find additional folders with names like Images, Media, Styles, Converters, CultureStrings, etc.  Some of these folders (Images, Media) are likely to contain embedded binary files, whereas others (Styles, Converters, CultureStrings) are likely to contain resource dictionaries for application resources.  The markup for the application class will typically contain references that merge in the appropriate application-wide resources.

<Application x:Class="StructureMatters.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:src="clr-namespace:StructureMatters"
    Startup="ApplicationStartup">
  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/presentationframework.aero;component/themes/aero.normalcolor.xaml" />
        <ResourceDictionary Source="/StructureMatters;component/Resources/Converters/ValueConverters.xaml"/>
        <ResourceDictionary Source="/StructureMatters;component/Resources/Icons/CommonGlyphs.xaml"/>
        <ResourceDictionary Source="/StructureMatters;component/Resources/Icons/CustomCursors.xaml"/>
        <ResourceDictionary Source="/StructureMatters;component/Resources/Styles/NativeControlStyles.xaml"/>
        <ResourceDictionary Source="/StructureMatters;component/Resources/Styles/EditModeControlStyles.xaml"/>
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>
</Application>

The code-behind for the application class may selectively merge in additional resource dictionaries.  For example, if the application needs to support dynamic locale switching, the appropriate UI culture resources will be merged into the application resources at startup.  A different dictionary of localized resources may later be swapped in if the user changes locale.

Organize Projects by Usage Scenarios

If a class is going to provide functionality that will be needed in other projects outside of your current application, go ahead and create a separate project for it within your solution and build it into a separate assembly.  Use project references to ensure that the correct dependencies are created between the different projects in your solution.  In this area, Visual Studio makes it very easy to develop solutions that share code across multiple assemblies.

Leverage the Object-Oriented Nature of the Platform

Hey, did you know that WPF is built on an object-oriented framework called .NET?  I’m sure you did Sacha.  I’m being a bit facetious here because a good deal of code I’ve seen recently leads me to believe that this concept is foreign to a lot of people.  (I plan to do a separate blog on some of my pet peeves in this particular area.  For some reason, perfectly good OO developers seem to toss out a lot of their OO skills when they begin writing WPF code.)

The reason I bring this object-oriented notion up here in a discussion on project structure is because the arrangement of class files within a solution should typically be related to the actual class hierarchies contained therein. 

If I’m looking at a class that provides data access functionality, it should be located alongside the other classes that provide similar functionality.  Furthermore, if they can leverage shared base functionality, data access classes should derive from a common base class.  The base class files should be located in a logical location in relationship to their derived classes (such as alongside them or maybe in a primitives directory, assuming the base classes are not expected to be instantiated directly).

Use Meaningful File Names and Namespaces

My recommendation is that a single code file should never contain more than one class (unless we’re talking about a nested class).  Furthermore, the filename of that code file should exactly match the name of its contained class. 

If code files are arranged within project folders, the folder hierarchy should match the namespace hierarchy for the contained classes.  For example, a C# class named BetterVisualTreeHelper within the DrWPF.Windows.Media namespace should be found within a file named BetterVisualTreeHelper.cs located within the folder path DrWPF\Windows\Media.

Visual Studio will do its best to assist you in this effort by creating default namespaces for new code files that match your project’s folder structure.

Keep Your XAML Files Editable in Blend

If you have skilled designers working on the project, they will probably be far more productive when they can edit the UI files directly in Blend.  In version 1.0 of Blend, there are still a few things that will cause a XAML file to fail to load within the Blend design surface.  These are usually small things that can be avoided or worked around.  Make sure that your designers are regularly opening the XAML files in Blend because it is much easier to isolate what caused a failure if you discover the failure soon after the offending change.  I’d love to provide an exhaustive list of the things to avoid, but such a list would very quickly become outdated, so I’ll just recommend going to the Blend/WPF forums when you have questions about markup that won’t open in Blend.

The same guidance can also be offered for the VS 2008 designer (a.k.a., Cider).  Unlike Blend, this product is still in Beta so expect to find more problematic areas at this stage.

The good news is that with each new pre-release of Blend 2.0 and Cider, there are fewer and fewer compatibility issues.  Soon, this whole topic will hopefully become a non-issue.

Revalidate Structure Regularly

Every project evolves.  I said it up front and I’ll say it again now.  You should revisit your project structure on a regular basis.  If you do this, you can make changes along the way to accommodate the changing nature of the project.

Now Get Started

Your project cannot even begin to take its proper structure until you begin to structure your project.  So go ahead and get started… just plan to make changes in structure whenever they become necessary.

I’m sure I’ve left out some obvious things here, so I welcome others out there to chime in with your recommendations on project structure.

Cheers!
Dr. WPF