Is there any way to use StaticResource in a WPF control library and be able to view at design-time?
I've run into this problem once, and I resolved it by dropping the whole "Resources are objects indexed by key in canonical dictionaries" thing.
I mean, the simple fact of defining a resource in one project and referencing it in another by it's "key" should give goosebumps to any sane person. I wanted strong references.
My solution to this problem was to create a custom tool that converts my resource xaml files to static classes with a property for each resource:
So MyResources.xaml:
<ResourceDictionary> <SolidColorBrush x:Key="LightBrush" ... /> <SolidColorBrush x:Key="DarkBrush" ... /></ResourceDictionary>
Becomes MyResources.xaml.cs
public static class MyResources { static MyResources() { // load the xaml file and assign values to static properties } public static SolidColorBrush LightBrush { get; set; } public static SolidColorBrush DarkBrush { get; set; }}
For referencing a resource, you can use the x:Static
instead of StaticResource
:
<Border Fill="{x:Static MyResources.LightBrush}" BorderBrush="{x:Static MyResources.DarkBrush}" ... />
Now you got strong references, autocompletion and compile time check of resources.
I too had a problem dealing with Styling Themes and available static resources. So, I created a stand-alone library that basically had nothing but the themes to be used all nested like your MERGED resources of your prior linked question.
Then, in the Windows form (.xaml), I just put reference to that library, something like
<Window x:Class="MyAppNamespace.MyView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ... /> <Window.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <!-- Common base theme --> <ResourceDictionary Source="pack://application:,,,/MyLibrary;component/Themes/MyMainThemeWrapper.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Window.Resources> <Rest of XAML for the WPF window></Window>
The "component" appears to refer to the root of the given "MyLibrary" project. In the actual project, I created a subfolder called "Themes", hence the source includes... ;component/Themes/...
The "MyMainThemeWrapper.xaml" is very much like your nested Merged Resource dictionaries, and it sees everything perfectly from other libraries.
Here's my partial solution to your problem. I haven't tried to handle loose resources, but I have some success with sharing resources between WinForms and WPF.
- Create a class library to contain your resources in .ResX files (e.g. Resources.resx, Resources.fr.resx, etc)
- Create your WPF controls in a WPF user control library
- Create your WinForms host
Reference the resources in your resource library from WPF using the Infralution.Localization.Wpf markup extension and culture manager, e.g.
<TextBlock Text="{Resx ResxName=ResourceLib.Resources, Key=Test}"/>
Put the content of your WPF user controls into one or more resource dictionaries as control templates,e,g
<ControlTemplate x:Key="TestTemplate"> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <TextBlock Text="{Resx ResxName=ResourceLib.Resources, Key=Test}"/> </Grid></ControlTemplate>
Use the resource template in your user controls
<UserControl x:Class="WpfControls.UserControl1" 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" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" > <UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="ResourceDictionary.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </UserControl.Resources> <ContentControl Template="{StaticResource TestTemplate}" /></UserControl>
Add a couple of lines of code to make things work
public partial class UserControl1 : UserControl{ // we require a reference to the resource library to ensure it's loaded into memory private Class1 _class1 = new Class1(); public UserControl1() { // Use the CultureManager to switch to the current culture CultureManager.UICulture = Thread.CurrentThread.CurrentCulture; InitializeComponent(); }}
Here's a simple demo app called WindowsFormsHost.7z