FrameworkElement`s DataContext Property does NOT i

2019-01-19 01:19发布

问题:

Hello WPF Pros at least I hope some of you read this!

DataContext is a property on FrameworkElement (base class for all WPF Controls) and is implemented as a DependencyProperty. That means all the descendant elements in the logical tree share the same DataContext.

So the ContentControl should do it with its descendant elements right?

I have a scenario where that is NOT the case and I would like to know WHAT is the cause of that misbehaviour ?!

That you understand a bit more about it please read this thread ( dont NOT want to copy everything here) where the trouble starts...:

WPF: Can not find the Trigger target 'cc'. The target must appear before any Setters, Triggers

and to say it in short words: My DataTemplates within the ContentControl do have a dead DataContext that means there is NOTHING to bind to it, what is actually not possible...

Every Element down the ContentControl has NOTHING set in the DataContext Property ???

回答1:

DataContext is a property on FrameworkElement (base class for all WPF Controls) and is implemented as a DependencyProperty. That means all the descendant elements in the logical tree share the same DataContext.

The fact that it's a dependency property doesn't imply inheritance... It's true for DataContext, but only because the dependency property has the FrameworkPropertyMetadataOptions.Inherits flag in its metadata.

So the ContentControl should do it with its descendant elements right?

ContentControl is a bit special: the DataContext of its descendants (the visual tree built from the DataTemplate) is actually be the Content of the ContentControl. So if your ContentControl has no content, the DataContext inside it is null.



回答2:

This worked for me:

<ContentControl ContentTemplate="{StaticResource NotesTemplate}"
                Content="{Binding}"
                DataContext="{Binding HeightField}"/>

Without the Content="{Binding}", the DataContext was NULL



回答3:

The last answer (from VinceF) worked for me too.

I wanted to show a usercontrol depending on the value of a property in my viewmodel. So I made a ContentControl with some Style Triggers. Depending on the value of a bind property the trigger sets a specific ContentTemplate containing the specific usercontrol.

The usercontrol was shown right, but its DataContext was always null. So I had to set the Context of the ContentControl to: Content="{Binding}" After that, the UserControls worked fine and had the same DataContext as their parent.

So my XAML looks like that:

In the Resources part I defined two DataTemplates; each one for each UserControl I want to show.

<DataTemplate x:Key="ViewA">
    <namespace:UserControlA/>
</DataTemplate>
<DataTemplate x:Key="ViewB">
    <namespace:UserControlB/>
</DataTemplate>

The part where I show the UserControl depending on a property is the following:

<ContentControl Content="{Binding}">
    <ContentControl.Style>
        <Style>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Property}" Value="0">
                    <Setter Property="ContentControl.ContentTemplate" Value="{StaticResource ViewA}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=Property}" Value="1">
                    <Setter Property="ContentControl.ContentTemplate" Value="{StaticResource ViewB}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>
</ContentControl>


回答4:

after reading this question and previous answers, I prefer using ContentControl with data triggered Content like this:

Controls which will be set as Content of ContentControl:

<TextBox x:Key="ViewA">
   ...
</TextBox>
<ComboBox x:Key="ViewB">
   ...
</ComboBox>

ContentControl which switch own content by DataTrigger in ContentControl style:

<ContentControl>
  <ContentControl.Style>
    <Style>
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=Property}" Value="0">
                <Setter Property="Content" Value="{StaticResource ViewA}" />
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=Property}" Value="1">
                <Setter Property="Content" Value="{StaticResource ViewB}" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
  </ContentControl.Style>
</ContentControl>

I hope this helps to someone like previous answers to me.