我有一个工作custom markup extension,它以特定的方式从DataContext
中检索信息(对于这个问题不重要)。
一直都很好,直到我在不属于视觉或逻辑树的元素中使用此标记扩展。在元素InputBindings
中的特定示例中。在此方案中,我没有将FrameworkElement
检索为DependencyObject
,而是Freezable
(KeyBinding
)。
如何通过代码访问 DataContext
?
我的XAML代码:
<UserControl.InputBindings>
<KeyBinding
Key="CapsLock"
Command="{wtc:CommandBinding {x:Static b:Commands.OpenTimeLine}}" />
</UserControl.InputBindings>
自定义标记扩展程序中的代码,我通常会检索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 );
}
整个源代码也在线。我有一个非常广泛的类层次结构用于标记扩展。
AbstractMarkupExtension⇐AbstractDependencyPropertyBindingExtension⇐AbstractDataContextBindingExtension⇐CommandBindingExtension
答案 0 :(得分:2)
一种解决方案非常容易。假设您要查找的DataContext
与根对象的DataContext
相同,则只需使用IRootObjectProvider
。可以通过IServiceProvider
访问此提供程序,ProvideValue
作为var rootProvider = (IRootObjectProvider)ServiceProvider
.GetService( typeof( IRootObjectProvider ) );
_frameworkElement = rootProvider.RootObject as FrameworkElement;
的参数传递。
DataContext
可能有更复杂的情况,您必须遍历树(通过LogicalChildren
)才能找到所需的{{1}}。
答案 1 :(得分:0)
这将是讨厌的反思方式:
var context = (FrameworkElement)typeof(DependencyObject)
.GetProperty("InheritanceContext", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(dependencyObject, null);
var datacontext = context.DataContext;
(对FrameworkElement
的投射不安全,InheritanceContext
也是DependencyObject
类型,InheritanceContext
通常是声明对象的对象使用Freezable
的属性,如果它不是FrameworkElement
,则可能需要递归)