Почему DataContext не наследуется на объектах, созданных как присоединенные свойства? - PullRequest
2 голосов
/ 05 февраля 2020

При создании объекта в xaml DataContext, по-видимому, в большинстве случаев правильно разрешается, но создание этого же объекта непосредственно в области действия Присоединенного свойства, по-видимому, блокирует наследование DataContext.

В этом случае Есть несколько определений, необходимых для отдыха. Я рад показать код, но для краткости вот схема:

  1. Модель представления, ViewModel, со свойством, ViewModel.MyProperty типа string, установленного на "123456789abc"
  2. Пользовательский объект, class FrameworkObject : FrameworkElement - пользовательский интерфейс не определен, но имеет DataContext. Этот объект имеет определенное свойство зависимости string FrameworkObject.MyDependencyProperty
  3. Присоединенное свойство AttachedProperty.FrameworkObject, которое принимает объект типа FrameworkObject
  4. A. Net Framework WPF Application, где мы проведет тестирование

Создание объекта как элемента в Visual Tree успешно связывает значение

    <!--
        System.Windows.Data Warning: 56 : Created BindingExpression (hash=52203868) for Binding (hash=27504314)
        System.Windows.Data Warning: 58 :   Path: 'MyProperty'
        System.Windows.Data Warning: 60 : BindingExpression (hash=52203868): Default mode resolved to OneWay
        System.Windows.Data Warning: 61 : BindingExpression (hash=52203868): Default update trigger resolved to PropertyChanged
        System.Windows.Data Warning: 62 : BindingExpression (hash=52203868): Attach to StackOverflowExamples.FrameworkObject.MyProperty (hash=34181910)
        System.Windows.Data Warning: 67 : BindingExpression (hash=52203868): Resolving source
        System.Windows.Data Warning: 70 : BindingExpression (hash=52203868): Found data context element: FrameworkObject (hash=34181910) (OK)
        System.Windows.Data Warning: 78 : BindingExpression (hash=52203868): Activate with root item ViewModel (hash=66824994)
        System.Windows.Data Warning: 108 : BindingExpression (hash=52203868):   At level 0 - for ViewModel.MyProperty found accessor RuntimePropertyInfo(MyProperty)
        System.Windows.Data Warning: 104 : BindingExpression (hash=52203868): Replace item at level 0 with ViewModel (hash=66824994), using accessor RuntimePropertyInfo(MyProperty)
        System.Windows.Data Warning: 101 : BindingExpression (hash=52203868): GetValue at level 0 from ViewModel (hash=66824994) using RuntimePropertyInfo(MyProperty): '123456789abc'
        System.Windows.Data Warning: 80 : BindingExpression (hash=52203868): TransferValue - got raw value '123456789abc'
        System.Windows.Data Warning: 89 : BindingExpression (hash=52203868): TransferValue - using final value '123456789abc'
    -->
    <local:FrameworkObject x:Name="CreatedInPanel" MyDependencyProperty="{Binding MyProperty, diag:PresentationTraceSources.TraceLevel=High}" />
    <TextBlock local:AttachedProperty.FrameworkObject="{Binding Path='', ElementName=CreatedInPanel}" Style="{StaticResource DisplayFromAttached}" />

Создание объекта в области действия TextBlock не может быть правильно привязано

        <!--
        System.Windows.Data Warning: 56 : Created BindingExpression (hash=53517805) for Binding (hash=3663598)
        System.Windows.Data Warning: 58 :   Path: 'MyProperty'
        System.Windows.Data Warning: 60 : BindingExpression (hash=53517805): Default mode resolved to OneWay
        System.Windows.Data Warning: 61 : BindingExpression (hash=53517805): Default update trigger resolved to PropertyChanged
        System.Windows.Data Warning: 62 : BindingExpression (hash=53517805): Attach to StackOverflowExamples.FrameworkObject.MyProperty (hash=51442863)
        System.Windows.Data Warning: 67 : BindingExpression (hash=53517805): Resolving source
        System.Windows.Data Warning: 70 : BindingExpression (hash=53517805): Found data context element: FrameworkObject (hash=51442863) (OK)
        System.Windows.Data Warning: 71 : BindingExpression (hash=53517805): DataContext is null
        System.Windows.Data Warning: 65 : BindingExpression (hash=53517805): Resolve source deferred
        System.Windows.Data Warning: 67 : BindingExpression (hash=53517805): Resolving source
        System.Windows.Data Warning: 70 : BindingExpression (hash=53517805): Found data context element: FrameworkObject (hash=51442863) (OK)
        System.Windows.Data Warning: 71 : BindingExpression (hash=53517805): DataContext is null
        System.Windows.Data Warning: 67 : BindingExpression (hash=53517805): Resolving source
        System.Windows.Data Warning: 70 : BindingExpression (hash=53517805): Found data context element: FrameworkObject (hash=51442863) (OK)
        System.Windows.Data Warning: 71 : BindingExpression (hash=53517805): DataContext is null
        System.Windows.Data Warning: 67 : BindingExpression (hash=53517805): Resolving source
        System.Windows.Data Warning: 70 : BindingExpression (hash=53517805): Found data context element: FrameworkObject (hash=51442863) (OK)
        System.Windows.Data Warning: 71 : BindingExpression (hash=53517805): DataContext is null
        System.Windows.Data Warning: 67 : BindingExpression (hash=53517805): Resolving source  (last chance)
        System.Windows.Data Warning: 70 : BindingExpression (hash=53517805): Found data context element: FrameworkObject (hash=51442863) (OK)
        System.Windows.Data Warning: 78 : BindingExpression (hash=53517805): Activate with root item <null>
        System.Windows.Data Warning: 106 : BindingExpression (hash=53517805):   Item at level 0 is null - no accessor
        System.Windows.Data Warning: 80 : BindingExpression (hash=53517805): TransferValue - got raw value {DependencyProperty.UnsetValue}
        System.Windows.Data Warning: 88 : BindingExpression (hash=53517805): TransferValue - using fallback/default value ''
        System.Windows.Data Warning: 89 : BindingExpression (hash=53517805): TransferValue - using final value ''
    -->
    <TextBlock Style="{StaticResource DisplayFromAttached}">
        <local:AttachedProperty.FrameworkObject>
            <local:FrameworkObject x:Name="CreatedInScope" MyDependencyProperty="{Binding MyProperty, diag:PresentationTraceSources.TraceLevel=High}" />
        </local:AttachedProperty.FrameworkObject>
    </TextBlock>

Использование прокси-сервера данных разрешит привязку даже при создании в области управления элемента управления

        <!--
        System.Windows.Data Warning: 56 : Created BindingExpression (hash=6968762) for Binding (hash=14964341)
        System.Windows.Data Warning: 58 :   Path: 'DataContext.MyProperty'
        System.Windows.Data Warning: 60 : BindingExpression (hash=6968762): Default mode resolved to OneWay
        System.Windows.Data Warning: 61 : BindingExpression (hash=6968762): Default update trigger resolved to PropertyChanged
        System.Windows.Data Warning: 62 : BindingExpression (hash=6968762): Attach to StackOverflowExamples.FrameworkObject.MyProperty (hash=47145209)
        System.Windows.Data Warning: 67 : BindingExpression (hash=6968762): Resolving source
        System.Windows.Data Warning: 70 : BindingExpression (hash=6968762): Found data context element: <null> (OK)
        System.Windows.Data Warning: 78 : BindingExpression (hash=6968762): Activate with root item FrameworkElement (hash=339559)
        System.Windows.Data Warning: 108 : BindingExpression (hash=6968762):   At level 0 - for FrameworkElement.DataContext found accessor DependencyProperty(DataContext)
        System.Windows.Data Warning: 104 : BindingExpression (hash=6968762): Replace item at level 0 with FrameworkElement (hash=339559), using accessor DependencyProperty(DataContext)
        System.Windows.Data Warning: 101 : BindingExpression (hash=6968762): GetValue at level 0 from FrameworkElement (hash=339559) using DependencyProperty(DataContext): <null>
        System.Windows.Data Warning: 106 : BindingExpression (hash=6968762):   Item at level 1 is null - no accessor
        System.Windows.Data Warning: 80 : BindingExpression (hash=6968762): TransferValue - got raw value {DependencyProperty.UnsetValue}
        System.Windows.Data Warning: 88 : BindingExpression (hash=6968762): TransferValue - using fallback/default value ''
        System.Windows.Data Warning: 89 : BindingExpression (hash=6968762): TransferValue - using final value ''
        System.Windows.Data Warning: 96 : BindingExpression (hash=6968762): Got PropertyChanged event from FrameworkElement (hash=339559) for DataContext
        System.Windows.Data Warning: 101 : BindingExpression (hash=6968762): GetValue at level 0 from FrameworkElement (hash=339559) using DependencyProperty(DataContext): ViewModel (hash=66824994)
        System.Windows.Data Warning: 108 : BindingExpression (hash=6968762):   At level 1 - for ViewModel.MyProperty found accessor RuntimePropertyInfo(MyProperty)
        System.Windows.Data Warning: 104 : BindingExpression (hash=6968762): Replace item at level 1 with ViewModel (hash=66824994), using accessor RuntimePropertyInfo(MyProperty)
        System.Windows.Data Warning: 101 : BindingExpression (hash=6968762): GetValue at level 1 from ViewModel (hash=66824994) using RuntimePropertyInfo(MyProperty): '123456789abc'
        System.Windows.Data Warning: 80 : BindingExpression (hash=6968762): TransferValue - got raw value '123456789abc'
        System.Windows.Data Warning: 89 : BindingExpression (hash=6968762): TransferValue - using final value '123456789abc'
    -->
    <ContentControl Content="{StaticResource DataProxy}" Visibility="Collapsed" />
    <TextBlock Style="{StaticResource DisplayFromAttached}">
        <local:AttachedProperty.FrameworkObject>
            <local:FrameworkObject x:Name="DataProxyBinding" MyDependencyProperty="{Binding DataContext.MyProperty, Source={StaticResource DataProxy}, diag:PresentationTraceSources.TraceLevel=High}" />
        </local:AttachedProperty.FrameworkObject>
    </TextBlock>

И самое сбивающее с толку меня. Построение FrameworkObject в пределах ContentControl.Content, кажется, отлично связывает

        <!--
        System.Windows.Data Warning: 56 : Created BindingExpression (hash=63642613) for Binding (hash=38750844)
        System.Windows.Data Warning: 58 :   Path: 'MyProperty'
        System.Windows.Data Warning: 60 : BindingExpression (hash=63642613): Default mode resolved to OneWay
        System.Windows.Data Warning: 61 : BindingExpression (hash=63642613): Default update trigger resolved to PropertyChanged
        System.Windows.Data Warning: 62 : BindingExpression (hash=63642613): Attach to StackOverflowExamples.FrameworkObject.MyProperty (hash=16347077)
        System.Windows.Data Warning: 67 : BindingExpression (hash=63642613): Resolving source
        System.Windows.Data Warning: 70 : BindingExpression (hash=63642613): Found data context element: FrameworkObject (hash=16347077) (OK)
        System.Windows.Data Warning: 78 : BindingExpression (hash=63642613): Activate with root item ViewModel (hash=66824994)
        System.Windows.Data Warning: 108 : BindingExpression (hash=63642613):   At level 0 - for ViewModel.MyProperty found accessor RuntimePropertyInfo(MyProperty)
        System.Windows.Data Warning: 104 : BindingExpression (hash=63642613): Replace item at level 0 with ViewModel (hash=66824994), using accessor RuntimePropertyInfo(MyProperty)
        System.Windows.Data Warning: 101 : BindingExpression (hash=63642613): GetValue at level 0 from ViewModel (hash=66824994) using RuntimePropertyInfo(MyProperty): '123456789abc'
        System.Windows.Data Warning: 80 : BindingExpression (hash=63642613): TransferValue - got raw value '123456789abc'
        System.Windows.Data Warning: 89 : BindingExpression (hash=63642613): TransferValue - using final value '123456789abc'
    -->
    <ContentControl x:Name="ImplicitContent">
        <ContentControl.Template>
            <ControlTemplate TargetType="ContentControl">
                <TextBlock local:AttachedProperty.FrameworkObject="{TemplateBinding Content}" Style="{StaticResource DisplayFromAttached}" />
            </ControlTemplate>
        </ContentControl.Template>

        <local:FrameworkObject MyDependencyProperty="{Binding MyProperty, diag:PresentationTraceSources.TraceLevel=High}" />
    </ContentControl>

. В этом я использовал стиль DisplayFromAttached, который находится в словаре ресурсов вложенной панели. и определяется следующим образом:

<Style x:Key="DisplayFromAttached" TargetType="TextBlock">
    <Setter Property="Text" Value="{Binding Path=(local:AttachedProperty.FrameworkObject).MyDependencyProperty, RelativeSource={RelativeSource Self}}" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path=(local:AttachedProperty.FrameworkObject).MyDependencyProperty, RelativeSource={RelativeSource Self}}" Value="">
            <Setter Property="Text" Value="No value found" />
        </DataTrigger>
    </Style.Triggers>
</Style>

Почему DataContext не наследуется объекту, созданному непосредственно как присоединенное свойство?

1 Ответ

3 голосов
/ 05 февраля 2020

С чего бы это?

Давайте вспомним, что FrameworkElement.DataContext реализован как DependencyProperty с флагом наследования (см. Источник кода здесь , строка 2704) и по этой причине «наследование» DataContext, о котором вы говорите, происходит в соответствии с документированными правилами наследования :

Наследование значений свойств включает дочерние элементы в дереве элементов для получения значения определенного свойства из родительских элементов.

Наследование значений свойств, в частности, касается того, как значения свойств могут наследоваться от одного элемента к другому на основе отношения родитель-ребенок в дереве элементов

В вашем случае нет таких отношений родитель-ребенок между вашим TextBlock и его значением AttachedProperty.FrameworkObject, не в смысле WPF , Факт, что это свойство зависимости или нет, на самом деле не влияет.


Некоторые комментарии к вашим попыткам

Создание объект как элемент в визуальном дереве успешно связывает значение

Да, потому что тогда объект наследует тот же DataContext, что и TextBlock, поскольку они имеют одного и того же родителя в дереве элементов.

Создание объекта в области TextBlock не может быть правильно привязано

Да, потому что TextBlock не является родительским для объекта в дереве элементов. TextBlock просто содержит ссылку на этот объект (здесь я скрываю сложность вложенных свойств).

Использование прокси-сервера данных разрешит привязку даже при создании в области видимости элемента управления

Да, потому что этот объект является потомком самого ContentControl, потомка элемента с правильным DataContext.

И самым странным для меня , Построение FrameworkObject внутри ContentControl.Content, кажется, отлично связывается.

То же, что и выше.


Если вам действительно нужен , чтобы ваш объект имел DataContext во втором сценарии вы должны установить его самостоятельно, поскольку он не будет наследоваться естественным путем:

<TextBlock x:Name="textBlock" Style="{StaticResource DisplayFromAttached}">
    <local:AttachedProperty.FrameworkObject>
        <local:FrameworkObject DataContext="{Binding ElementName=textBlock, Path=DataContext}" x:Name="CreatedInScope" MyDependencyProperty="{Binding MyProperty, diag:PresentationTraceSources.TraceLevel=High}" />
    </local:AttachedProperty.FrameworkObject>
</TextBlock>
...