I looked at a lot of topics, but they all in one way or another are related to the definition of the DataContext of UI elements.
I have a task that requires a completely different approach. And no matter how much I puzzled over the decision, I could not think of anything.
Description of the problem.
Initially, there is a simple proxy:
using System;
using System.Windows;
namespace Proxy
{
/// <summary> Provides a <see cref="DependencyObject"/> proxy with
/// one property and an event notifying about its change. </summary>
public class Proxy : Freezable
{
/// <summary> Property for setting external bindings. </summary>
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(Value), typeof(object), typeof(Proxy), new PropertyMetadata(null));
protected override Freezable CreateInstanceCore()
{
throw new NotImplementedException();
}
}
}
If you set it in the Resources of any element, then it can get the DataContext with a simple Binding:
<FrameworkElement.Resources>
<proxy:ProxyValue x:Key="proxy"
Value="{Binding}"/>
</FrameworkElement.Resources>
Likewise, any Bindig without an explicitly specified source will use the DataContext of the element in whose resources the proxy instance is declared as the source.
Child proxy injection.
Now, for a certain task (its conditions are not relevant to the question, so I will not describe it) I needed a nested (child) proxy which can also be assigned a binding relative to the data context.
And I need to set this binding in code.
A highly simplified example for demonstration:
using System.Windows.Data;
namespace Proxy
{
public class PregnantProxy : Proxy
{
public Proxy Child { get; } = new Proxy();
public PregnantProxy()
{
Binding binding = new Binding();
BindingOperations.SetBinding(this, ValueProperty, binding);
BindingOperations.SetBinding(Child, ValueProperty, binding);
}
}
}
<StackPanel DataContext="Some data">
<FrameworkElement.Resources>
<proxy:PregnantProxy x:Key="proxy"/>
</FrameworkElement.Resources>
<TextBlock Text="{Binding}" Margin="10"/>
<TextBlock Text="{Binding Value, Source={StaticResource proxy}}" Margin="10"/>
<TextBlock Text="{Binding Child.Value, Source={StaticResource proxy}}" Margin="10"/>
</StackPanel>
Parent proxy binding works as expected.
But linking a child will not return anything.
How can you set the correct binding for a child?
For now, I've implemented a working solution with finding the parent FrameworkElement and adding a child proxy to the resources of the parent FrameworkElement.
The test use case shown in the question works correctly.
But such a solution may throw an exception if the resources are locked or read-only.
The final solution.
The answer from @Rekshino pushed me to look for a solution in a different direction.
I created an extension method to set a DependencyObject's context relative to another DependencyObject.
The method can be applied to any DependecyObject.
But context-relative bindings are only interpreted by Freezable. So it makes little sense for the rest of the DependecyObject.
But maybe I missed something, and I can somehow use it or modify it.
Usage example.
The XAML shown in the question works correctly with such an implementation.
If someone has comments on the code and possible problems with such an implementation, I am ready to listen carefully.