为什么 DataContext 无法继承构造为附加属性的对象?

Why does DataContext fail to inherit on objects constructed as attached properties?

在 xaml 中构建对象时,DataContext 似乎大多数时候都能正确解析,但直接在 Attached 属性 的范围内构建同一对象似乎会阻止 DataContext 继承。

在这里面,有几个娱乐需要的定义。我很乐意展示代码,但为了简洁起见,这里是大纲:

  1. 视图模型,ViewModel,属性,ViewModel.MyProperty 类型字符串设置为 "123456789abc"
  2. 自定义对象,class FrameworkObject : FrameworkElement - 未定义 UI,但有一个 DataContext。此对象具有已定义的依赖项 属性、string FrameworkObject.MyDependencyProperty
  3. 附加的 属性、AttachedProperty.FrameworkObject,它采用类型 FrameworkObject
  4. 的对象
  5. 我们将在其中进行测试的 .Net Framework WPF 应用程序

创建对象作为可视化树中的元素成功绑定值

    <!--
        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 WhosebugExamples.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 WhosebugExamples.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 WhosebugExamples.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>

最让我困惑的是。在 ContentControl.Content 中构建 FrameworkObject 似乎可以很好地绑定

        <!--
        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 WhosebugExamples.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 无法继承到直接构造为 Attached 属性 的对象?

为什么会这样?

让我们记住 FrameworkElement.DataContext 是作为带有继承标志的 DependencyProperty 实现的(参见代码源 here, line 2704) and as such, the "inheritance" of the DataContext you are talking about takes place according to the documented inheritance rules:

Property value inheritance enables child elements in a tree of elements to obtain the value of a particular property from parent elements.

Property value inheritance is particularly about how property values can inherit from one element to another on the basis of the parent-child relationships within a tree of elements

在你的情况下,你的 TextBlock 和它的 AttachedProperty.FrameworkObject 值之间没有这种父子关系,不是 WPF 意义上的。它是附加还是非依赖项这一事实 属性 实际上没有影响。


对您的尝试的一些评论

Creating the object as an element in the Visual Tree successfully binds the value

是的,因为对象继承了与 TextBlock 相同的 DataContext,因为它们在元素树中具有相同的父级。

Creating the object within the scope of the TextBlock fails to bind properly

是的,因为 TextBlock 不是元素树中对象的父对象。 TextBlock 恰好持有对该对象的引用(我在这里隐藏了附加属性的复杂性)。

Using a data proxy will resolve the binding even when created in a control's scope

是,因为该对象是 ContentControl 的子对象,它本身是具有正确 DataContext 的元素的子对象。

And the most confusing to me. Constructing the FrameworkObject within a ContentControl.Content seems to bind perfectly fine.

同上


如果你真的需要你的对象在你的第二种情况下有一个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>