Thursday, August 28, 2008   Search 
Links

 

Disciple
 Ask Dr. WPF Minimize
Author: Dr. WPF Created: 8/13/2007 5:15 PM
Do you have questions about Windows Presentation Foundation that might have broad appeal? Ask Dr. WPF!

Continuing Quest for "Star"-dom
By Dr. WPF on 10/25/2007 4:45 PM

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.

Comments (4)

ItemsControl: 'B' is for Bet You Can't Find Them All!
By Dr. WPF on 10/22/2007 2:20 PM

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

Comments (9)

ToolTip Positioning
By Dr. WPF on 10/16/2007 1:01 PM

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

 
Comments (5)

ItemsControl: 'A' is for Abundance
By Dr. WPF on 10/15/2007 9:42 AM

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!"

 

Comments (11)

Enhancing Developer/Designer Productivity
By Dr. WPF on 10/8/2007 2:31 PM

"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.

Comments (1)

Managing Application Resources when WPF is Hosted
By Dr. WPF on 10/6/2007 2:46 AM

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)