繁体   English   中英

如果目标不是 FrameworkElement,如何在代码隐藏中设置 DynamicResource?

[英]How can you set a DynamicResource in code-behind if the target is not a FrameworkElement?

考虑这个 BindingProxy 类,它是 Freezable 的子类(因此它在添加到FrameworkElementResources集合时参与资源层次结构查找)...

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 ,因此它会按预期自动跟踪对该键定义的资源的更改。

现在,如果您想在代码隐藏而不是 XAML 中设置DynamicResource ,如果目标对象是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是如何工作的“肉”——是内部的,所以我也无法做到这一点。

因此,在代码隐藏中,如何在基于Freezable的对象上设置DynamicResource以反映我可以在 XAML 中执行的操作?

您可以在代码中使用DynamicResourceExtension实例:

var proxy = new BindingProxy();
var dynamicResourceExtension = new DynamicResourceExtension("TestValue");
proxy.Value = dynamicResourceExtension.ProvideValue(null);

如果您在此处看到代码参考您将看到当serviceProvider为 null 时, ProvideValue返回一个ResourceReferenceExpression SetResourceReference所做的几乎相同

使用反射创建一个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的值,则您无能为力。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM