Introduction
Many developers have trouble with designer support of WPF styles, which are defined in another assembly, and should be referenced using DynamicResource
and ComponentResourceKey
. I will show you how to solve this problem by writing a very simple MarkupExtension
.
Background
The main problem of the XAML designer when working with external ResourceDictionaries
, and impossibility to have App.xaml with included:
<Application x:Class="ResTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary Source="pack://application:,,,/SF.Styles;component/General.xaml" />
</Application.Resources>
</Application>
It cannot load specific style assembly and cannot resolve ResourceKey
.
<Button Style="{DynamicResource ResourceKey=MyButton}" />
Many developers use a well known cure for this, which includes using of ComponentResourceKey
, Static class with style names and very difficult two side bindings (in Styles project and in Own project).
You can read about this implementation, for example, here.
Let's Do It...
All that we need - is to write a small portion of code.
Create base class with abstract MarkupExtension
using System;
using System.Windows;
using System.Windows.Markup;
namespace WPFExtensions
{
public abstract class StyleRefExtension : MarkupExtension
{
protected static ResourceDictionary RD;
public String ResourceKey { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if(RD == null) throw new Exception(
@"You should define RD before usage.
Please make it in static constructor of extending class!");
return RD[ResourceKey];
}
}
}
Create our styles assembly with any resource dictionaries and one compound dictionary
Buttons.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Button" x:Key="MyButton">
<Setter Property="Background" Value="Green" />
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="40" />
<Setter Property="Content" Value="Hello from style" />
</Style>
</ResourceDictionary>
General.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionaries/Buttons.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Create class in styles assembly which will extend abstract StyleRefExtension
:
using System;
using System.Windows;
using WPFExtensions;
namespace MyStyles
{
public class MyStyleRefExtension : StyleRefExtension
{
static MyStyleRefExtension()
{
RD = new ResourceDictionary()
{
Source = new Uri("pack://application:,,,/MyStyles;component/General.xaml")
};
}
}
}
You can use this class in any project and XAML designer will show you your styles.
For example, I will create a WinForms project and will add WPF user control, and for example will use DynamicResource
with referenced assembly:
Yes, not working as expected...
Now, we will use our new extension:
And... that is what we wanted.
History
-
07/02/2013 - Article creation