Как вы можете установить DynamicResource в коде позади, если целью не является FrameworkElement? - PullRequest
0 голосов
/ 03 сентября 2018

Рассмотрим этот класс BindingProxy, который является подклассом Freezable (поэтому он участвует в поисках иерархии ресурсов при добавлении в коллекцию FrameworkElement s 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 s, поэтому вы не можете использовать его для BindingProxy.

Копаясь в исходном коде для FrameworkElement.SetResourceReference, вы найдете это ...

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

К сожалению, ResourceReferenceExpression - «мясо» того, как это работает, - внутреннее, поэтому я тоже не могу добраться до этого.

Так что в коде позади, как я могу установить DynamicResource на моем Freezable объекте для отражения того, что я могу сделать в XAML?

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

Вы можете использовать экземпляр DynamicResourceExtension в своем коде:

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

Если вы видите кодовую ссылку здесь , вы увидите, что ProvideValue возвращает ResourceReferenceExpression, когда serviceProvider равно нулю. Почти то же самое, что SetResourceReference делает

0 голосов
/ 03 сентября 2018

Создать 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 динамически.

...