Redefine/alias a resource in WPF?

前端 未结 3 1089
野趣味
野趣味 2020-12-06 04:42

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 ResourceDic

相关标签:
3条回答
  • 2020-12-06 05:27
    <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.

    0 讨论(0)
  • 2020-12-06 05:32

    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.

    0 讨论(0)
  • 2020-12-06 05:35

    You can try to tuse the StaticResourceExtension, but in global resource dictionaries this does not work (strange compiler and runtime errors):

    <ResourceDictionary 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    
        <SolidColorBrush x:Key="StatusColor_OK" Color="#ff32a248" />
        <StaticResourceExtension
            x:Key="AliasKey"
            ResourceKey="StatusColor_Error" />
    </ResourceDictionary>
    

    To overcome this problem, I created the following class:

    /// <summary>
    /// Defines an Alias for an existing resource. Very similar to 
    /// <see cref="StaticResourceExtension"/>, but it works in
    ///  ResourceDictionaries
    /// </summary>
    public class Alias: System.Windows.Markup.MarkupExtension
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            IRootObjectProvider rootObjectProvider = (IRootObjectProvider)
                serviceProvider.GetService(typeof (IRootObjectProvider));
            if (rootObjectProvider == null) return null;
            IDictionary dictionary =  rootObjectProvider.RootObject as IDictionary;
            if (dictionary == null) return null;
            return dictionary[ResourceKey];
        }
    
    
        public object ResourceKey { get; set; }
    }
    

    Usage:

    <ResourceDictionary 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    
        <SolidColorBrush x:Key="StatusColor_OK" Color="#ff32a248" />
        <Alias
            x:Key="AliasKey"
            ResourceKey="StatusColor_Error" />
    </ResourceDictionary>
    
    0 讨论(0)
提交回复
热议问题