Reputation: 30368
Consider this BindingProxy class which is a subclass of Freezable (so it participates in resource-hierarchy lookups when added to a FrameworkElement
's Resources
collection)...
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
}
You add it to your XAML like so...
<Window.Resources>
<is:BindingProxy x:Key="TestValueProxy" Value="{DynamicResource TestValue}" />
</Window.Resources>
As you can see, Value
is set to a DynamicResource
and it will thus automatically track changes to a resource defined by that key, as expected.
Now if you wanted to set up a DynamicResource
in code-behind instead of XAML, if the target object is a FrameworkElement
, you would simply call SetResourceReference
on it, like so...
myTextBlock.SetResourceReference(TextBlock.TextProperty, "MyTextResource")
However, SetResourceReference
is only available on FrameworkElement
objects, not Freezable
s so you can't use that on BindingProxy
.
Digging into the source code for FrameworkElement.SetResourceReference
, you find this...
public void SetResourceReference(DependencyProperty dp, object name){
base.SetValue(dp, new ResourceReferenceExpression(name));
HasResourceReference = true;
}
Unfortunately, ResourceReferenceExpression
--the 'meat' of how this works--is internal so I can't get to that either.
So in code-behind, how can I set a DynamicResource
on my Freezable
-based object to mirror what I can do in XAML?
Upvotes: 1
Views: 1335
Reputation: 2767
You can use a DynamicResourceExtension
instance in your code:
var proxy = new BindingProxy();
var dynamicResourceExtension = new DynamicResourceExtension("TestValue");
proxy.Value = dynamicResourceExtension.ProvideValue(null);
If you see the code reference here you will see that ProvideValue
returns a ResourceReferenceExpression
when serviceProvider
is null. Just almost the same thing that SetResourceReference
does
Upvotes: 2
Reputation: 169200
Create a ResourceReferenceExpression
using reflection:
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);
Obviously this code may break if the internal type changes, but there is not much else you can do if you really need to be able to apply a DynamicResource
to a value of a Freezable
dynamically.
Upvotes: 0