Rati_Ge
Rati_Ge

Reputation: 1270

WPF SharedResourceDictionary

I have used a custom class to implement shared resource functionality in my WPF application this is a sample code to create and manage dictionaries

public class SharedResourceDictionary : ResourceDictionary
{
    /// <summary>
    /// Internal cache of loaded dictionaries 
    /// </summary>
    public static Dictionary<Uri, ResourceDictionary> SharedDictinaries = new Dictionary<Uri, ResourceDictionary>();

    /// <summary>
    /// Local member of the source uri
    /// </summary>
    private Uri _sourceUri;

    private static bool IsInDesignMode
    {
        get
        {
            return (bool)DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty,
                                                                   typeof(DependencyObject)).Metadata.DefaultValue;
        }
    }

    /// <summary>
    /// Gets or sets the uniform resource identifier (URI) to load resources from.
    /// </summary>
    public new Uri Source
    {
        get
        {
            if (IsInDesignMode)
            {
                return base.Source;
            }
            return _sourceUri;
        }
        set
        {
            if (!IsInDesignMode)
            {
                base.Source = value;
                return;
            }
            _sourceUri = value;
            if (!SharedDictinaries.ContainsKey(value))
            {
                base.Source = value;
                SharedDictinaries.Add(value, this);
            }
            else
            {
                MergedDictionaries.Add(SharedDictinaries[value]);
            }
        }
    }
}

this File is implemented i a separate assembly and I have refferenced it in my shell WPF application.

I have my resources defined in app.xaml int the following way

    <Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <Infrastructure:SharedResourceDictionary Source="pack://application:,,,/CuratioCMS.Client.Resources;Component/Themes/General/Brushes.xaml" />
            <Infrastructure:SharedResourceDictionary Source="pack://application:,,,/Fluent;Component/Themes/Office2010/Silver.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
   </Application.Resources>

if I remove Brushes.xaml it works but with this dictinary in place as I switch to design view I get following error

Exception has been thrown by the target of an invocation

could someone help my to figure out the problem?

Upvotes: 2

Views: 7131

Answers (3)

Hugge
Hugge

Reputation: 21

I know this issue is old and solved, but as I have been working on an alternative solution with a friend, I wanted to share it:

  1. Use the WPF ResourceDictionary everywhere in xaml, this way Blend and the VS designer does not break.
  2. Reference nuget packages Sundew.Xaml.Optimizations and Sundew.Xaml.Optimizer
  3. Add a sxo-settings.json in the root of your project and enable the ResourceDictionaryCachingOptimizer
  4. Build
    The build will use a caching/shared ResourceDictionary.

For more details see: https://github.com/hugener/Sundew.Xaml.Optimizations
And the sample: https://github.com/hugener/Sundew.Xaml.Optimizer.Sample

Upvotes: 1

J. Lennon
J. Lennon

Reputation: 3361

To solve this problem I did (I really wanted to work at design time in VisualStudio 2010):

public string SourcePath { get; set; }

public new Uri Source
{
    get
    {
        if (IsInDesignMode)
        {
            return base.Source;
        }
        else
        {
            return _sourceUri;
        }

    }
    set
    {
        if (value == null)
            return;

        if (IsInDesignMode)
        {
            var dict = Application.LoadComponent(new Uri(SourcePath, UriKind.Relative)) as ResourceDictionary;
            MergedDictionaries.Add(dict);
            return;
        }

        _sourceUri = value;
        if (!_sharedDictionaries.ContainsKey(value))
        {
            base.Source = value;

            _sharedDictionaries.Add(value, this);
        }
        else
        { 
            MergedDictionaries.Add(_sharedDictionaries[value]);
        }
    }
}

and in my XAML:

<SharedResourceDictionary SourcePath="JooThemes;component/Buttons/Small/SettingsToggleStyle.xaml" Source="/JooThemes;component/Buttons/Small/SettingsToggleStyle.xaml" />

Upvotes: 3

gReX
gReX

Reputation: 1080

I read somewhere, that it is a memory issue @design-time. I solved it in the Setter of Source:

/// <summary>
/// Gets or sets the uniform resource identifier (URI) to load resources from.
/// </summary>
public new Uri Source
{
    get { return _sourceUri; }
    set
    {
        _sourceUri = value;
        if (!_sharedDictionaries.ContainsKey(value))
        {
            try
            {
                 //If the dictionary is not yet loaded, load it by setting
                 //the source of the base class
                base.Source = value;
            }
            catch (Exception exp)
            {
                //only throw exception @runtime to avoid "Exception has been 
                //thrown by the target of an invocation."-Error@DesignTime
                if( ! IsInDesignMode )
                    throw;
            }
            // add it to the cache
            _sharedDictionaries.Add(value, this); 
        }
        else
        {
            // If the dictionary is already loaded, get it from the cache 
            MergedDictionaries.Add(_sharedDictionaries[value]); 
        }                 
    }
}

Upvotes: 0

Related Questions