Как вы можете установить DynamicResource в коде позади, если целью не является FrameworkElement?
Рассмотрим этот класс 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 ответа
Вы можете использовать DynamicResourceExtension
экземпляр в вашем коде:
var proxy = new BindingProxy();
var dynamicResourceExtension = new DynamicResourceExtension("TestValue");
proxy.Value = dynamicResourceExtension.ProvideValue(null);
Если вы видите ссылку на код здесь, вы увидите, что ProvideValue
возвращает ResourceReferenceExpression
когда serviceProvider
нулевой. Просто почти то же самое, что 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
динамически.