Переопределить / псевдоним ресурс в WPF?
Есть ли способ переопределить / псевдоним существующего SolidColorBrush
(или любой другой ресурс, на самом деле)?
Пример: у меня есть кисть во внешнем ResourceDictionary, на которую я хочу ссылаться своим собственным ключом вместо исходного ключа. Я не хочу зависеть от внешней ссылки, так как реальная кисть подвержена изменениям в будущем.
3 ответа
<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>
Я не хочу зависеть от внешней ссылки, так как реальная кисть подвержена изменениям в будущем.
Вы по-прежнему будете зависеть от внешнего ресурса, но не во многих местах.
У меня есть обновление для решения Ruedi Steinmann. Это работает для ресурсов как в одном словаре ресурсов, так и в любом месте приложения.
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;
}
}
Использование похоже на выше, но ключ должен использовать Alias
как расширение разметки, где используется, а не StaticResource
, Где-нибудь в стеке ресурсов приложения определите ресурсы...
<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>
И где бы вы ни ссылались на псевдонимы...
<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>
Мое решение требует ссылки на строки, но оно работает для любого объекта, который вы хотите псевдоним.
Вы можете попытаться использовать StaticResourceExtension, но в глобальных словарях ресурсов это не работает (странные ошибки компилятора и времени выполнения):
<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>
Чтобы преодолеть эту проблему, я создал следующий класс:
/// <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; }
}
Использование:
<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>