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

etb*_*erg 3 c# wpf xaml binding attached-properties

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

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

  1. 视图模型 ,ViewModel其属性ViewModel.MyProperty的字符串类型设置为"123456789abc"
  2. 自定义对象class FrameworkObject : FrameworkElement- 未定义 UI,但具有 DataContext。该对象具有定义的依赖属性,string FrameworkObject.MyDependencyProperty
  3. 附加属性 ,AttachedProperty.FrameworkObject它采用类型的对象FrameworkObject
  4. 我们将在其中进行测试的 .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 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}" />
Run Code Online (Sandbox Code Playgroud)

在 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>
Run Code Online (Sandbox Code Playgroud)

即使在控件的范围内创建,使用数据代理也将解析绑定

        <!--
        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>
Run Code Online (Sandbox Code Playgroud)

最让我困惑的是。FrameworkObject在 a 中构建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>
Run Code Online (Sandbox Code Playgroud)

通过这个,我使用了一种样式,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>
Run Code Online (Sandbox Code Playgroud)

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

Cor*_*ane 5

为什么会这样?

让我们记住,它FrameworkElement.DataContext是作为带有继承标志的实现(请参阅此处的DependencyProperty代码源,第 2704 行),因此,您所讨论的“继承”是根据记录的继承规则进行的:DataContext

属性值继承使元素树中的子元素能够从父元素获取特定属性的值。

属性值继承特别涉及属性值如何根据元素树中的父子关系从一个元素继承到另一个元素

TextBlock就您而言,您与其值之间不存在这种父子关系AttachedProperty.FrameworkObject,这不是 WPF 意义上的。它是附加属性还是非依赖属性这一事实实际上并没有影响。


对你的尝试的一些评论

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

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

在 TextBlock 范围内创建对象无法正确绑定

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

即使在控件的范围内创建,使用数据代理也将解析绑定

是的,因为该对象是 aContentControl本身的子级,也是具有正确DataContext.

最让我困惑的是。在 ContentControl.Content 中构造 FrameworkObject 似乎绑定得很好。

与上面相同。


如果您确实需要对象在第二种情况下具有 a 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>
Run Code Online (Sandbox Code Playgroud)