Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get WYSIWYG design in Blend/VS without merged ResourceDictionary in every XAML file?

I've just removed a big memory issue for me, I used to merge our "Themes" resource dictionary in every xaml file instead of just in the app.cs.xaml.

However, after removing the merging in every file except the App.cs.xaml I've lost the design time styles/templates.

Please note: This only applies to the styles merged into our Themes.xaml (e.g. Color.xaml, Brushes.xaml - we have one for each type of style). Stuff defined directly in Themes.xaml (which we have none of..) works.

I see two solutions,

1) Have the merging commented out in XAML and just un-comment it when I want to work with the designs.

2) Have this in the default ctor of every control: (perhaps only works in Blend)

#if DEBUG
Resources.MergedDictionaries.Add(
                new ResourceDictionary()
                {
                    Source = new System.Uri(@"RD.xml")
                }
                );
#endif

There has to be a better way to get design time editing of pages and controls, anyone know?

Thank you!

like image 526
andyhammar Avatar asked Jun 15 '09 08:06

andyhammar


3 Answers

Blend 4 supports "design time resources", which Visual Studio 2010 also supports. See http://adamkinney.wordpress.com/2010/05/04/design-time-resources-in-expression-blend-4-rc/.

It's pretty much just a ResourceDictionary that contains whatever MergedDictionaries you like, and shows up in the project file like this (automatically added by Blend):

<Page Include="Properties\DesignTimeResources.xaml" Condition="'$(DesignTime)'=='true' OR ('$(SolutionPath)'!='' AND Exists('$(SolutionPath)') AND '$(BuildingInsideVisualStudio)'!='true' AND '$(BuildingInsideExpressionBlend)'!='true')">
  <Generator>MSBuild:Compile</Generator>
  <SubType>Designer</SubType>
  <ContainsDesignTimeResources>true</ContainsDesignTimeResources>
</Page>

Works great.

like image 53
scobi Avatar answered Oct 17 '22 01:10

scobi


What I do is add a class that inherits from ResourceDictionary and override the source property to check if IsInDesignMode is true.

If it is I set the source otherwise I leave the source blank (which effectivley prevents the dictionary from being merged at runtime)

public class BlendMergedDictionary : ResourceDictionary
{
    public bool IsInDesignMode
    {
        get
        {
            return (bool)DependencyPropertyDescriptor.FromProperty(
                            DesignerProperties.IsInDesignModeProperty,
                            typeof(DependencyObject)
                            ).Metadata.DefaultValue;
        }
    }

    public new Uri Source
    {
        get { return base.Source; }
        set
        {
            if (!IsInDesignMode)
                return;

            Debug.WriteLine("Setting Source = " + value);
            base.Source = value;
        }
    }
}

Now when I need to reference the dictionary in Blend I merge in the dictionary like this

<ResourceDictionary.MergedDictionaries>
            <BlendHelpers:BlendMergedDictionary Source="Foo.xaml" />
</ResourceDictionary.MergedDictionaries>

You still have to "merge" in the dictionary in every file, but you don't pay the penalty of actually loading the dictionary at runtime. The merge is only there to support design time behavior.

like image 33
Brad Cunningham Avatar answered Oct 17 '22 02:10

Brad Cunningham


Janes question is actually related to this one, i have the same problem. i've created a subclass of ResourceDictionary like Foovanadil suggested, however at design time this throws a "Uri prefix not recodnized" exception

I get this error even if all the sub class does is assign the base.Source property of ResourceDictionary. If i replace my custom ResourceDictionary with the regular one, it works just fine, so im guessing the cider designer does someting special, perhaps replacing ResourceDictionary with something else

I havent tried this in blend but i do get it in VS2010 (sp1 beta) Can someone confirm that the posted awnser works in vs2010?

-edit-

Its possible that the wpf based designer is tripping up the resource locating logic. I've read elsewhere that pack uris are based on the -executing- assembly, not neccecarily the -local- assembly. i'll report whats i finds

-edit2/solution-

Alright so i managed to get Foovanadil solution to work in VS2010, here is the deal. Turns out i was half right, presumably because the wpf designer in VS2010 is itself written in wpf or to provide a better design experience, ResourceDictionary (or some other class that VS2010 uses instead) behaves diffrently at design time.

It turns out that VS replaces the URI that is entered in the xaml. Attatcing to the VS instance and setting a breakpoint in the setter for Source reveals that the actual value that is getting passed is diffrent from what we expect.

Given the xaml:

<Window.Resources>
  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
      <local:DesignTimeResourceDictionary Source="myxamlfile.xaml"  />
    </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
</Window.Resources>

Source is set to

markup://1/file:///c:/PathtoMyapp/MainWindow.xaml#0/myxamlfile.xaml

instead of

/myxamlfile.xaml

This is why we get the exception for invalid uris.

Exactly when and where VS2010 edits URIs this way at design time is not known to me, but it renaming the Source property in DesignTimeResourceDictionary to something else does not solve the problem.

Luckliy there is a workaround. If we change the type of Source from Uri to String, the VS designer does not modify the value. In the setter we then create a Uri and pass it to the base property:

public new String Source {
  get {
    return base.Source.ToString();
  }
  set {
    if( !IsInDesignMode )
      return;
    base.Source = new Uri( value, UriKind.RelativeOrAbsolute );
  }
}

Note also that if you use this approach (or any other that ive found such as using x:class in the resource file and instancing it directly from xaml) will cause styles not to get updated until you build. Using the standard ResourceDictionary will cause the designer to update as soon as you edit the imported resource files (even before you save). This is also an indication that the designer treats ResrouceDictionary diffrently at design time.

Hope someone finds this useful :)

like image 1
aL3891 Avatar answered Oct 17 '22 01:10

aL3891