2

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?

Russell Troywest
  • 8,475
  • 2
  • 32
  • 40
Rati_Ge
  • 1,244
  • 2
  • 15
  • 36
  • If you still have a problem, what's the inner exception if there is one? Also, you're solution configuration isn't set to x64 is it? That can cause mysterious problems in the design view. – Sheridan Jan 29 '12 at 02:13
  • what do u mean by set to x64? do u mean build configuration? no it is not set to x64 – Rati_Ge Jan 29 '12 at 18:55
  • Well I've just looked in Visual Studio and it's actually called 'Solution Platform', not solution configuration. But I gather that's not your problem then. – Sheridan Jan 29 '12 at 21:03

3 Answers3

3

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" />
J. Lennon
  • 3,211
  • 4
  • 32
  • 64
  • 1
    can you explain what was wrong and why u use SourcePath with source parameter? – Rati_Ge May 07 '12 at 07:57
  • Now think about it, really did not need the source property SourcePath! This could be circumvented otherwise.The question is: – J. Lennon May 07 '12 at 13:09
  • base.Source = value; cause exceptions at design time in Visual Studio 2010. Now the code: Application.LoadComponent only accepts relative paths, so I was setting in the Source property, Absolute or Relative path. And SourcePath only the relative path to be accepted and get the design-time visualization. – J. Lennon May 07 '12 at 13:15
1

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

Hugge
  • 21
  • 2
0

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]); 
            }                 
        }
    }
gReX
  • 1,489
  • 1
  • 20
  • 35
  • 1
    Ok I will try this but one question I have relates to using this type of dictionary. is it still necessary to use this approach in WPF 4? – Rati_Ge Feb 08 '12 at 09:42