Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bug in the Visual Studio WPF designer?

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.

like image 350
Ignacio Soler Garcia Avatar asked Jul 18 '13 09:07

Ignacio Soler Garcia


1 Answers

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.

like image 107
Will Eddins Avatar answered Oct 06 '22 22:10

Will Eddins