Question

I am busy building a custom control. The Theme has a Generic.xaml that consist of a MergedDictionary referencing 2 resource dictionaries (1 - Generic brush and 2 - ControlTemplate) which is situated in a Generic folder.

I have a tester project (standard Window) added to the solution to test the control.

Issue: When I add the control for the first time - the look of the control looks correct. However when I do some changes on the control and rebuild it - the control disappear from the window and I have to Unload the Window project and Reload it again to make the control's look reappear again.

When I run debugger the control does appear correctly - it is just in design mode that it becomes difficult to work with.

Is there a solution / workaround for this occurrence that does not involve unloading and reloading the window on each rebuild?

EDIT

I have run a test where I copied all the info from separate resource dictionaries into the Generic.Xaml and commented out the Merge Dictionary. It seems the issue does not lie with MergeDictionary operations as the problem is still there - but perhaps with ComponentResourceKey / or static properties. One of my ResourceDictionaries for instance contain a lot of the following

<SolidColorBrush x:Key="{x:Static keys:Disabled.ForeGroundKey}" Color="Gray"/>

Where ForeGroundKey is linked to a static class with for example:

public static class Normal
{
    static ComponentResourceKey _background = new ComponentResourceKey(typeof(G2ListBox),"ContainerBackground");
    public static ComponentResourceKey BackGroundKey
    { get { return _background; } }
}

I guess seeing that the theme work sometimes mean that there is nothing wrong with the above approach and there is something wrong with how VS handles the rebuild of the control. What I do not understand though is why doesn't VS recognize either the old values / new values, instead it ignores all values linked to ComponentResourceKey - Ps. during runtime the control works perfectly.

Was it helpful?

Solution

Well it seems like I have 3 options here.

  1. Use the method I have been using all along:

    • Define ComponentResourceKey in C# Class

      public static class Normal
      {
          static ComponentResourceKey _background = new ComponentResourceKey(typeof(G2ListBox), "Normal.Background");
      
          public static ComponentResourceKey BackGroundKey
          { get { return _background; } }
      }
      
    • Assign Key in Resource Dictionary

      <SolidColorBrush x:Key="{x:Static keys:Normal.BackGroundKey}" Color="Yellow"/>
      
    • Use Key in Resource Dictionary:

      <Setter Property="BorderBrush" Value="{DynamicResource {x:Static keys:Normal.BorderBrushKey}}"/>
      

    The advantage is that when you have multiple themes to assign and use the resource key seems simplistic and chances of errors occurring in typing over the name is reduced as you have the help of intelisence.
    The disadvantage is that when you are working on a large project, and you make a small adjustment to your control - none of the ComponentResourceKeys are loaded and your project looks completely lookless at design time. To fix this issue, one either has to reboot VS or unload the project that uses your control and reload it again. Ps this is only at design time. Running the project will give the correct result. This is a silly problem to have in VS!!

  2. return to the more verbose method of defining Component resource keys in XAML i.e.

    • Define and Assign the resourceKey.

      <SolidColorBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:G2ListBox}, ResourceId=Normal.Background}" Color="Yellow"/>
      
    • Use the resourceKey:

      <Setter Property="BorderBrush" Value="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type local:G2ListBox}, ResourceId=Normal.Background}}"/>
      

    The Advantage is VS is now working everytime in design time. Also you do not have to create a separate C# class to hold all your resourcekeys The Disadvantage is that you have to remember the ResourceId names for each resourceId and type it out as it was defined. Also using this in a control with multiple themes becomes frustrating.

  3. Use a mixture of the 2 above i.e.

    • You still Define the ResourceKey in C# library

    • You Assing the ResourceKey as per method 2. But the ResourceId is the "text" field assigned in the C# class and not the x:static method i.e.

      public static class Normal
      {
          static ComponentResourceKey _background = new ComponentResourceKey(typeof(G2ListBox), "Normal.Background");
      
          public static ComponentResourceKey BackGroundKey
          { get { return _background; } }
      }
      //To assign
      <SolidColorBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:G2ListBox}, ResourceId=Normal.Background}" Color="Yellow"/>
      //Thus Normal.Background and not Keys:Normal.Background!!  where keys = referenced to the C# Class
      
    • Then to use

      <Setter Property="Background" Value="{DynamicResource {x:Static keys:Normal.BackGroundKey}}"/>
      //i.e we now can reference the C# class and have intelisence
      

    The advantage is that 1 you have a static class that hold all the ResourceKeys in C# (goes slightly against lookless philosophy). you also have access to proper intelisence at least in the using side. But best of all VS works perfectly in design time. This however does not shorten the assign side at all and the disadvantages therefore are still that you need to type out verbose text to assign a color to the resourcekey. Having multiple themes each with its own set of colors means that you have only shorten the Style of the control a bit and seems silly to use this method

Thus if you want the best solution and do not care about the design time look I'd prefer option1. If you prefer design time visuals then I'd go for method 2 unless you have to define the style at a number of places too, then option 3 will suffice. Alternatively create a designtime ResouceDictionary and a compile time ResourceDictionary. Where at designtime method 3 is used and compile time method 2 -> Not sure how to do this automatically. I am doing this by use of Merged Dictionaries, and uncommenting the proper dictionary when Control is ready to be compiled, and deleting the designtime ResourceDictionary.

Hope this helps someone, some day as I had to spend the whole day trouble shooting this (I thought there was something wrong with my control - turns out there is something wrong with VS).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top