While constructing an object in xaml, the DataContext seems to resolve properly most of the time, but constructing that same object directly in the scope of an Attached Property seems to block DataContext inheritance.
In this, there are several definitions required for recreation. I'm happy to show the code, but for brevity's sake here is the outline:
- A view model,
ViewModel
, with a property,ViewModel.MyProperty
of type string set to"123456789abc"
- A custom object,
class FrameworkObject : FrameworkElement
- no UI defined, but has a DataContext. This object has a defined dependency property,string FrameworkObject.MyDependencyProperty
- An attached property,
AttachedProperty.FrameworkObject
, which takes an object of typeFrameworkObject
- A .Net Framework WPF Application where we will do the testing
Creating the object as an element in the Visual Tree successfully binds the value
<!--
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}" />
Creating the object within the scope of the TextBlock fails to bind properly
<!--
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>
Using a data proxy will resolve the binding even when created in a control's scope
<!--
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>
And the most confusing to me. Constructing the FrameworkObject
within a ContentControl.Content
seems to bind perfectly fine
<!--
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>
Through this, I've used a style, DisplayFromAttached
, which is found in the enclosing panel's resource dictionary and is defined thus:
<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>
Why does the DataContext fail to inherit to an object constructed directly as an Attached Property?