0

FrameworkElement考虑这个 BindingProxy 类,它是 Freezable 的一个子类(因此当添加到 a的集合时它参与资源层次结构查找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设置为 a DynamicResource,因此它将自动跟踪对该键定义的资源的更改,如预期的那样。

现在,如果您想在代码隐藏中设置 aDynamicResource而不是 XAML,如果目标对象是 a FrameworkElement,您只需调用SetResourceReference它,就像这样......

myTextBlock.SetResourceReference(TextBlock.TextProperty, "MyTextResource")

但是,SetResourceReference仅适用于FrameworkElement对象,而不适用于Freezables,因此您不能在BindingProxy.

深入研究 的源代码FrameworkElement.SetResourceReference,您会发现...

public void SetResourceReference(DependencyProperty dp, object name){
    base.SetValue(dp, new ResourceReferenceExpression(name));
    HasResourceReference = true;
}

不幸ResourceReferenceExpression的是,它的工作原理是内部的,所以我也无法做到这一点。

所以在代码隐藏中,我如何在基于DynamicResourceFreezable的对象上设置一个来反映我在 XAML 中可以做什么?

4

2 回答 2

1

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

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

如果您在此处看到代码参考,您将看到ProvideValue返回一个ResourceReferenceExpressionwhenserviceProvider为 null。几乎一样的SetResourceReference事情

于 2018-09-03T16:24:07.250 回答
0

创建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);

显然,如果内部类型发生更改,此代码可能会中断,但如果您确实需要能够动态地将 a 应用于DynamicResourcea 的值,则您无能为力Freezable

于 2018-09-03T15:53:45.690 回答