6

Check the following scenario (others may apply as well) [you can create the project just copy pasting the code here on the right file]:

a - Create a ResourceDictionary with basic stuff (Resources.xaml):

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

    <SolidColorBrush Color="Red" x:Key="Test" />

    <Style TargetType="{x:Type GroupBox}" x:Key="Test2" >
        <Setter Property="Background" Value="Blue" />
    </Style>

    <Style TargetType="{x:Type TextBlock}" >
        <Setter Property="Foreground" Value="Green" />
    </Style>
</ResourceDictionary>

b - Create a user control base where others will inherit containing basic resources (UserControlBase.cs):

using System.Windows.Controls;
using System;
using System.Windows;

namespace ResourceTest
{
    public class UserControlBase : UserControl
    {
        public UserControlBase()
        {
            this.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("ResourceTest;component/Resources.xaml", UriKind.RelativeOrAbsolute) });
        }
    }
}

c - Create a UserControl inheriting from the base (UserControl1.xaml):

<ResourceTest:UserControlBase x:Class="ResourceTest.UserControl1"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:ResourceTest="clr-namespace:ResourceTest"

             mc:Ignorable="d" 

             d:DesignHeight="300" 
             d:DesignWidth="300" >
    <Grid>
        <GroupBox BorderBrush="{StaticResource Test}" Margin="3" Header="Test" Style="{DynamicResource Test2}" >
            <TextBlock Text="TESTTEST" />
        </GroupBox>

    </Grid>
</ResourceTest:UserControlBase>

Results: StaticResources are not resolved (and the Test BorderBrush is not loaded). DynamicResources are resolved (the background is blue) but the designer says that it cannot find the resource anyway (the first time works ok but when you open/close the designer the resource cannot be resolved). Non named resources like the TextBlock style work ok.

Is this a designer bug or am I doing something wrong? Is ok to have to declare the resources as dynamic in an scenario where the resources will never change?

enter image description here

Thanks in advance.

Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207
  • It's okay to declare resources as dynamic, just not as efficient. If you're using this ResourceDictionary only here, have you tried adding it in `UserControl.Resources` in a XAML front for the base class to see if it behaves differently? – Will Eddins Jul 18 '13 at 12:41
  • @WillEddins: in my real application the resources are set on a base UserControl so every control has the required resources to see it right on the WPF designer (otherwise the styles are only applied on runtime and we cannot do proper UI design unless starting the app on each change :S). – Ignacio Soler Garcia Jul 18 '13 at 12:55

1 Answers1

1

It appears the designer has trouble resolving MergedDictionaries that are defined in the code-behind at design-time.

An even worse example can be seen by moving the ResourceDictionary to before your Initialize.

public UserControl1()
{
    this.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("TempProject;component/Resources.xaml", UriKind.RelativeOrAbsolute) });
    InitializeComponent();
}

In this case, the DynamicResource even fails to resolve at design-time, indicating the design-time view is not necessarily calling the constructors as you may expect. I tested this with Visual Studio 2012, so this behavior has not changed since 2010.

in terms of your original test code, note that the StaticResource does successfully bind as expected at run-time (the red border appears), regardless of the "error" thrown and lack of a red border by the design-time view.

I see two options:

  1. Use DynamicResource where necessary to resolve these at design-time. While you can use StaticResource, the associated "errors" and lack of design-time view would clearly be a problem. Other answers seem to indicate there may not be much performance difference between the two now.

  2. Simply instantiate the ResourceDictionary in your UserControl.Resources, and don't inherit from a base class. While you're condensing a bit of code using a base class, you're not being any more efficient, since a new ResourceDictionary instance is going to be created everytime. Since you can't (AFAIK) extend from a base class with a XAML front-end, you could potentially argue against having an unreferenced MergedDictionary at this level of abstraction.

Community
  • 1
  • 1
Will Eddins
  • 13,628
  • 5
  • 51
  • 85
  • Thanks Will for the time you spent on this. We are currently using approach 1 but I am a bit worried with the warning (even if it does not hurt it shouldn't be there). Solution 2 it is not an option as the base class resources are a bit complex (you can change the style of the application at run-time) so there are several resource dictionaries involved. To make things harder we want to see the controls at designtime like in runtime so we are adding the resourcedictionaries only at designtime (otherwise they come from the App). That's why we created a base UserControl ... – Ignacio Soler Garcia Jul 18 '13 at 13:55
  • Do you think that we should file a bug to Ms? – Ignacio Soler Garcia Jul 18 '13 at 13:56
  • @SoMoS I'd be interested in hearing from someone who's more familiar with how the designer works in terms of constructor calls and whatnot. However, in terms of changing style at runtime, I'd usually expect to see a `ResourceDictionary` changed at the `Application.Resources` level. Even if you defined the `ResourceDictionary` in the example as static (so it's shared when added), you'd still have to change the MergedDictionary on a per-instance basis, wouldn't you? I'm sure your implementation is different, but it seems a complicated way to go about it. – Will Eddins Jul 18 '13 at 14:05
  • the fact is that the dictionaries are only merged in Design time as we only need them to see the UserControl in a proper way into the editor. In runtime the dictionaries won't be merged as they are taken from application.resources, off course. We are developing a modular app with PRISM and the app resources are far away from us at design time :) – Ignacio Soler Garcia Jul 18 '13 at 14:14