如何在自定义MarkupExtension中处理Freezable?

时间:2012-01-27 16:33:19

标签: c# wpf xaml

我有一个工作custom markup extension,它以特定的方式从DataContext中检索信息(对于这个问题不重要)。

一直都很好,直到我在不属于视觉或逻辑树的元素中使用此标记扩展。在元素InputBindings中的特定示例中。在此方案中,我没有将FrameworkElement检索为DependencyObject,而是FreezableKeyBinding)。

如何通过代码访问 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 );
}

整个源代码也在线。我有一个非常广泛的类层次结构用于标记扩展。

AbstractMarkupExtensionAbstractDependencyPropertyBindingExtensionAbstractDataContextBindingExtensionCommandBindingExtension

2 个答案:

答案 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,则可能需要递归)