Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redefine/alias a resource in WPF?

Tags:

resources

wpf

Is there a way to redefine/alias an existing SolidColorBrush (or any other resource, actually)?

Case in point: I have a brush in an external ResourceDictionary that I want to reference by my own key instead of the original key. I don't want to be dependent on the external reference, since the actual brush is prone to change in the future.

like image 350
Inferis Avatar asked Mar 11 '09 11:03

Inferis


2 Answers

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <SolidColorBrush x:Key="SomeExternalResource">Red</SolidColorBrush>
    </Window.Resources>
    <Grid>
        <Grid.Resources>
            <StaticResourceExtension ResourceKey="SomeExternalResource" x:Key="SomeAliasedResource"/>
        </Grid.Resources>

        <Border Background="{StaticResource SomeAliasedResource}"/>
    </Grid>
</Window>

I don't want to be dependent on the external reference, since the actual brush is prone to change in the future.

You'll still be dependent on the external resource, just not in as many places.

like image 149
Kent Boogaart Avatar answered Sep 22 '22 09:09

Kent Boogaart


I have an update to Ruedi's solution. This works for resources both within the same resource dictionary and anywhere within the application.

public class Alias : MarkupExtension
{
    public string ResourceKey { get; set; }

    public Alias()
    {

    }
    public Alias(string resourceKey)
    {
        ResourceKey = resourceKey;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return _ProvideLocalValue(serviceProvider) ?? _ProvideApplicationValue();
    }

    private object _ProvideLocalValue(IServiceProvider serviceProvider)
    {
        var rootObjectProvider = (IRootObjectProvider)
            serviceProvider.GetService(typeof(IRootObjectProvider));
        if (rootObjectProvider == null) return null;
        var dictionary = rootObjectProvider.RootObject as IDictionary;
        if (dictionary == null) return null;
        return dictionary.Contains(ResourceKey) ? dictionary[ResourceKey] : null;
    }

    private object _ProvideApplicationValue()
    {
        var value = Application.Current.TryFindResource(ResourceKey);
        return value;
    }
}

The usage is similar to above, but the key is to use Alias as the markup extension where used, not StaticResource. Somewhere in the application resource stack, define the resources...

<Application x:Class="WPF.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:system="clr-namespace:System;assembly=mscorlib"
             xmlns:wpf="clr-namespace:WPF"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <system:String x:Key="Text">Display some text.</system:String>
        <system:String x:Key="Other">4</system:String>
        <wpf:Alias x:Key="Alias" ResourceKey="Text"/>
        <wpf:Alias x:Key="Second" ResourceKey="Other"/>
    </Application.Resources>
</Application>

And wherever you're referencing the aliases...

<Window x:Class="WPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpf="clr-namespace:WPF"
        Title="MainWindow" Height="150" Width="300">
    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
        <TextBlock Text="{wpf:Alias Alias}"/>
        <TextBlock Text="{wpf:Alias Second}"/>
    </StackPanel>
</Window>

My solution required referencing strings, but it works for any object you want to alias.

like image 25
gregsdennis Avatar answered Sep 22 '22 09:09

gregsdennis