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,635
  • 3
  • 35
  • 40
Rati_Ge
  • 1,262
  • 2
  • 15
  • 37
  • 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" />
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
J. Lennon
  • 3,311
  • 4
  • 33
  • 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

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
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]); 
        }                 
    }
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
gReX
  • 1,060
  • 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