Как обработать Freezable в пользовательском MarkupExtension? - PullRequest
4 голосов
/ 27 января 2012

У меня есть рабочее пользовательское расширение разметки , которое извлекает информацию из 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

Ответы [ 2 ]

2 голосов
/ 30 января 2012

Одно решение на удивление легко.Предполагая, что DataContext, который вы ищете, совпадает с DataContext вашего корневого объекта, вы можете просто использовать IRootObjectProvider.Этот провайдер доступен через IServiceProvider, который передается в качестве аргумента ProvideValue.

var rootProvider = (IRootObjectProvider)ServiceProvider
                       .GetService( typeof( IRootObjectProvider ) );
_frameworkElement = rootProvider.RootObject as FrameworkElement;

. Могут быть более сложные сценарии, когда вам нужно пройти по дереву (через LogicalChildren) чтобы найти желаемое DataContext.

0 голосов
/ 27 января 2012

Вот был бы отвратительный способ отражения:

var context = (FrameworkElement)typeof(DependencyObject)
    .GetProperty("InheritanceContext", BindingFlags.NonPublic | BindingFlags.Instance)
    .GetValue(dependencyObject, null);
var datacontext = context.DataContext;

(приведение к FrameworkElement является не безопасным, InheritanceContext также имеет тип DependencyObject, InheritanceContext обычно является объектом, объявляющим свойство, в котором используется Freezable , если это не FrameworkElement, вам может понадобиться повторение)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...