I’ve got a working custom markup extension which retrieves information out of the DataContext in a specific way (unimportant for this question).
All is well until I use this markup extension in elements that are not part of the visual or logical tree. In my particular example in the element InputBindings. In this scenario instead of retrieving a FrameworkElement as DependencyObject I get a Freezable (KeyBinding).
How can I access the DataContext through code?
My XAML code:
<UserControl.InputBindings>
<KeyBinding
Key="CapsLock"
Command="{wtc:CommandBinding {x:Static b:Commands.OpenTimeLine}}" />
</UserControl.InputBindings>
Code in my custom markup extension where I normally retrieve my DataContext:
protected override object ProvideValue(
DependencyObject dependencyObject,
DependencyProperty dependencyProperty )
{
if ( dependencyObject is Freezable )
{
// TODO: How to handle freezable?
}
_frameworkElement = dependencyObject as FrameworkElement;
if ( _frameworkElement == null )
{
throw new InvalidImplementationException(
"The DataContextBinding may only be used on framework elements." );
}
if ( !_dataContextChangedHooked )
{
_frameworkElement.DataContextChanged += DataContextChanged;
_dataContextChangedHooked = true;
}
return ProvideValue( _frameworkElement.DataContext );
}
The entire source code is online as well. I have quite an extensive class hierarchy for markup extensions.
AbstractMarkupExtension ⇐ AbstractDependencyPropertyBindingExtension ⇐ AbstractDataContextBindingExtension ⇐ CommandBindingExtension
One solution is surprisingly easy. Assuming the
DataContextyou are looking for is the same as theDataContextof your root object you can simply use theIRootObjectProvider. This provider is accessible through theIServiceProviderwhich is passed as an argument ofProvideValue.There might be more complex scenarios where you have to traverse the tree (through
LogicalChildren) in order to find the desiredDataContext.