views:

1333

answers:

3

I have custom classes that I currently instantiate within App.xaml as resources. I want to move these custom objects into a Merged ResourceDictionary, where they are used within styles, and keep them close to where they are used. Here's an example of what I want, arbitrarily using fake converter objects, but they could be any custom object...

App.xaml (namespace declarations ommitted):

<Application.Resources>
<ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Merged.xaml" />
    </ResourceDictionary.MergedDictionaries>
    <Style x:Key="SomeStyle" TargetType="SomeControl">
        ...
    </Style>
    ...

</ResourceDictionary>

And then in Merged.xaml (namespace declarations omitted):

<ResourceDictionary>
    <cvt:VisibilityToBoolConverter x:Key="BoolToVisibility" Inverted="True"/>
    <cvt:VisibilityToBoolConverter x:Key="NotBoolToVisibility" Inverted="True" Not="True"/>

    <Style x:Key="SomethingThatUsesVisibilityToBoolConvertersStyle" TargetType="SomeOtherControl">
        ....
    </Style>
</ResourceDictionary>

The issue I'm seeing is this: when I create the BoolToVisibility and NotBoolToVisibility objects (as well instantiating other objects that are instances of custom classes I have created) just as part Application.Resources, they are created and all the references work as expected; however, when I move these into a Merged Resource Dictionary (as I have in the sample above), I get a malformed Application exception when the Silverlight application loads.

I belive this to be an issue with how objects are instantiated differently in Merged Resource Dictionaries (I belive it is more of a lazy-load approach), but I would expect it to work nonetheless.

I am very much able to add Style objects, DataTemplates, ControlTemplates, and the like. But when I want to create instances of custom classes that are named or keyed using Xaml, it works great inside of App.xaml's Application.Resources directly and Application.Resources/ResourceDictionary as well. As soon as they are moved into a merged dictionary, it throws the exception. Is this by design? Any other ideas that work? Thanks in advance...

A: 

I have FINALLY worked around this. I took a page out of how the App class gets instantiated and did the same with the Merged.xaml file. I created a class with "code-behind" for Merged.xaml, called Merged that inherits from ResourceDictionary. I then (borrowing from App.g.cs), I initialize the component by loading from the Merged.xaml file during construction.

Merged.xaml.cs:

public partial class Merged : ResourceDictionary
{
    private bool _contentLoaded;

    public Merged()
    {
        InitializeComponent();
    }

    public void InitializeComponent() 
    {
        if (_contentLoaded) 
        {
            return;
        }
        _contentLoaded = true;
        System.Windows.Application.LoadComponent(this, new System.Uri("/MySilverlightApp;component/Merged.xaml", System.UriKind.Relative));
    }
}

The Merged.xaml file looks exactly the same as in my original question, using ResourceDictionary as it's root element.
The App.xaml is SLIGHTLY different. Instead of referencing the Merged ResourceDictionary by using the ResourceDictionary element and the Source attribute, I simply referenced the Merged class:

<Application.Resources
xmlns:msa="clr-namespace:MySilverlightApplication">
<ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
        <msa:Merged />
    </ResourceDictionary.MergedDictionaries>
    <Style x:Key="SomeStyle" TargetType="SomeControl">
        ...
    </Style>
    ...
</ResourceDictionary>
</Application.Resources>

Viola! It works.

Tony Heupel
A: 

Hi Tony, very clever solution, thanks

Lothar
A: 

You can avoid the extra codebehind by setting the build action for your shared xaml to "Resource" and reference it as /AssemblyName;component/Shared.xaml. For a reason that mostly escapes me, referencing it in this way allows custom object instantiation to work properly.

blucz

related questions