如果目标不是 FrameworkElement,如何在代码隐藏中设置 DynamicResource?
How can you set a DynamicResource in code-behind if the target is not a FrameworkElement?
考虑这个 BindingProxy class,它是 Freezable 的子class(因此当添加到 FrameworkElement
的 Resources
集合时,它会参与资源层次结构查找)...
public class BindingProxy : Freezable {
public BindingProxy(){}
public BindingProxy(object value)
=> Value = value;
protected override Freezable CreateInstanceCore()
=> new BindingProxy();
#region Value Property
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
nameof(Value),
typeof(object),
typeof(BindingProxy),
new FrameworkPropertyMetadata(default));
public object Value {
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
#endregion Value Property
}
你像这样将它添加到你的 XAML...
<Window.Resources>
<is:BindingProxy x:Key="TestValueProxy" Value="{DynamicResource TestValue}" />
</Window.Resources>
如您所见,Value
设置为 DynamicResource
,因此它将按预期自动跟踪对该键定义的资源的更改。
现在,如果您想在代码隐藏中设置 DynamicResource
而不是 XAML,如果目标对象是 FrameworkElement
,您只需调用 SetResourceReference
就这样了...
myTextBlock.SetResourceReference(TextBlock.TextProperty, "MyTextResource")
但是,SetResourceReference
仅适用于 FrameworkElement
对象,不适用于 Freezable
,因此您不能在 BindingProxy
.
上使用它
深入研究 FrameworkElement.SetResourceReference
的源代码,您会发现...
public void SetResourceReference(DependencyProperty dp, object name){
base.SetValue(dp, new ResourceReferenceExpression(name));
HasResourceReference = true;
}
不幸的是,ResourceReferenceExpression
——关于它如何工作的 'meat'——是内部的,所以我也无法做到。
所以在代码隐藏中,我如何在基于 Freezable
的对象上设置 DynamicResource
来反映我在 XAML 中可以做什么?
使用反射创建 ResourceReferenceExpression
:
Type type = typeof(System.Windows.Window).Assembly.GetType("System.Windows.ResourceReferenceExpression");
ConstructorInfo ctor = type.GetConstructors()[0];
object resourceReferenceExpression = ctor.Invoke(new object[] { "TestValue" });
TestValueProxy.SetValue(BindingProxy.ValueProperty, resourceReferenceExpression);
显然,如果内部类型发生变化,此代码可能会中断,但如果您确实需要能够将 DynamicResource
应用于 Freezable
的值,则您无能为力。动态地。
您可以在代码中使用 DynamicResourceExtension
实例:
var proxy = new BindingProxy();
var dynamicResourceExtension = new DynamicResourceExtension("TestValue");
proxy.Value = dynamicResourceExtension.ProvideValue(null);
如果您看到代码参考 here,您会看到 ProvideValue
returns 一个 ResourceReferenceExpression
当 serviceProvider
为空时。 SetResourceReference
所做的几乎与
相同
考虑这个 BindingProxy class,它是 Freezable 的子class(因此当添加到 FrameworkElement
的 Resources
集合时,它会参与资源层次结构查找)...
public class BindingProxy : Freezable {
public BindingProxy(){}
public BindingProxy(object value)
=> Value = value;
protected override Freezable CreateInstanceCore()
=> new BindingProxy();
#region Value Property
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
nameof(Value),
typeof(object),
typeof(BindingProxy),
new FrameworkPropertyMetadata(default));
public object Value {
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
#endregion Value Property
}
你像这样将它添加到你的 XAML...
<Window.Resources>
<is:BindingProxy x:Key="TestValueProxy" Value="{DynamicResource TestValue}" />
</Window.Resources>
如您所见,Value
设置为 DynamicResource
,因此它将按预期自动跟踪对该键定义的资源的更改。
现在,如果您想在代码隐藏中设置 DynamicResource
而不是 XAML,如果目标对象是 FrameworkElement
,您只需调用 SetResourceReference
就这样了...
myTextBlock.SetResourceReference(TextBlock.TextProperty, "MyTextResource")
但是,SetResourceReference
仅适用于 FrameworkElement
对象,不适用于 Freezable
,因此您不能在 BindingProxy
.
深入研究 FrameworkElement.SetResourceReference
的源代码,您会发现...
public void SetResourceReference(DependencyProperty dp, object name){
base.SetValue(dp, new ResourceReferenceExpression(name));
HasResourceReference = true;
}
不幸的是,ResourceReferenceExpression
——关于它如何工作的 'meat'——是内部的,所以我也无法做到。
所以在代码隐藏中,我如何在基于 Freezable
的对象上设置 DynamicResource
来反映我在 XAML 中可以做什么?
使用反射创建 ResourceReferenceExpression
:
Type type = typeof(System.Windows.Window).Assembly.GetType("System.Windows.ResourceReferenceExpression");
ConstructorInfo ctor = type.GetConstructors()[0];
object resourceReferenceExpression = ctor.Invoke(new object[] { "TestValue" });
TestValueProxy.SetValue(BindingProxy.ValueProperty, resourceReferenceExpression);
显然,如果内部类型发生变化,此代码可能会中断,但如果您确实需要能够将 DynamicResource
应用于 Freezable
的值,则您无能为力。动态地。
您可以在代码中使用 DynamicResourceExtension
实例:
var proxy = new BindingProxy();
var dynamicResourceExtension = new DynamicResourceExtension("TestValue");
proxy.Value = dynamicResourceExtension.ProvideValue(null);
如果您看到代码参考 here,您会看到 ProvideValue
returns 一个 ResourceReferenceExpression
当 serviceProvider
为空时。 SetResourceReference
所做的几乎与