Adding a static ResourceDictionary to UserControls

2019-05-07 07:00发布

问题:

I have one WPF control that I want to use in my WinForms application (using an ElementHost) in several places (=> multiple instances of this control).

Furthermore I want all instances of my UserControl to share one single Instance of a ResourceDictionary.

In WPF applications I would achieve that by merging my ResourceDictionary in the Application Resources.

However, I don't want to create an WPF Application Instance in my WinForms application. Instead I am looking for another way.

I found one solution but I am hoping you know a better way that does not require any code behind:

    public static class StaticRDProvider
{
    static ResourceDictionary rd;
    static StaticRDProvider()
    {
        var uri = new Uri("WpfControls;Component/GlobalResourceDictionary.xaml", UriKind.Relative);
        rd = (ResourceDictionary) Application.LoadComponent(uri);
    }

    public static ResourceDictionary GetDictionary
    {
        get { return rd; }
    }
}

UserControl.xaml.cs:

    public partial class MyCustomUserControl : UserControl
{
    public MyCustomUserControl()
    {
        Resources.MergedDictionaries.Add(StaticRDProvider.GetDictionary);

        InitializeComponent();
    }
}

That works. But I prefer a solution that only works with XAML. Plus I want to be able to use StaticResources. Therefore adding the static ResourceDictionary to the Controls MergedDictionaries after the control was initialized is not an option.

I tried the following, but it throws a strange "stack is empty" exception:

<UserControl x:Class="WpfControls.MyCustomUserControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:WpfControls="clr-namespace:WpfControls" mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>                
            <x:Static Member="WpfControls:StaticRDProvider.GetDictionary"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>

</UserControl.Resources>
<Grid>
</Grid>

Maybe someone knows a better approach.

Thanks, TwinHabit

回答1:

Did you try loading the RD inside your UserControl the same you would do it with the Application class?

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>                
            <ResourceDictionary Source="WpfControls;Component/GlobalResourceDictionary.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>

This way you just specify the URI in your user control, and avoid the static members hassle altogether.

BTW, make sure to use the correct URI syntax if the RD is not in the same assembly as the UserControl. For example: pack://application:,,,/YourAssembly;component/Subfolder/YourResourceFile.xaml (more info on pack URIs)