none
How to databind the DataContext of a ContentPresenter's Content?

    Question

  • I have a ContainerWindow that has a ContentPresenter inside of it, defined using XAML. I have added a dependency proparty named ChildControl inside ContainerWindow so it can be databound to the ContentPresenter.Content.

    Then I have the class ContainerWindowViewModel that contains a property named ChildControlViewModel,  and I would like to databind that property to the ContentPresenter.Content's DataContext. Is it possible to express this in XAML or does it have to be done in the code behind?

    Thanks,

     

    XAML:

     

    <UserControl x:Class="MyNamespace.ContainerWindow">
        <ContentPresenter Content="{Binding RelativeSource={RelativeSource Self}, Path=ChildControl}" />
    </UserControl>

     

    ViewModel:

     

    class ContainerWindowViewModel
    {
        public object ChildControlViewModel
       {
            get { [...] }
            set { [...] }
        }
    }

     

     


    -Sylvain
    Thursday, June 10, 2010 6:01 PM

Answers

  • Hi Sylvain,

    There is a mistake in your code,
      <ContentPresenter Content="{Binding RelativeSource={RelativeSource Self}, Path=ChildControl}" />
    the "RelativeSource Self" references to the ContentPresenter self; but as you said, the ContentPresenter does not have the property ChildControl. So the correct is 
      <ContentPresenter Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type l:ContainerWindow}}, Path=ChildControl}" />

    And you can create a ContainerWindowViewModel instance in XAML by resources, then bind ContentPresenter.DataContext to this static resource.

    code snippet:

    <UserControl x:Class="MyNamespace.ContainerWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Height="300" Width="300"
      xmlns:l="clr-namespace:MyNamespace">
     <UserControl.Resources>
      <l:ContainerWindowViewModel x:Key="containerWindowViewModel"/>
     </UserControl.Resources>
     <ContentPresenter DataContext="{Binding Source={StaticResource containerWindowViewModel}, Path=ChildControlViewModel}"
              Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type l:ContainerWindow}}, Path=ChildControl}" />
    </UserControl>

    If you have any problem, please feel free to let me know.

    Sincerely,

    Bob Bao


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Monday, June 14, 2010 5:48 AM
    Moderator

All replies

  • Hi Sylvain,

    There is a mistake in your code,
      <ContentPresenter Content="{Binding RelativeSource={RelativeSource Self}, Path=ChildControl}" />
    the "RelativeSource Self" references to the ContentPresenter self; but as you said, the ContentPresenter does not have the property ChildControl. So the correct is 
      <ContentPresenter Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type l:ContainerWindow}}, Path=ChildControl}" />

    And you can create a ContainerWindowViewModel instance in XAML by resources, then bind ContentPresenter.DataContext to this static resource.

    code snippet:

    <UserControl x:Class="MyNamespace.ContainerWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Height="300" Width="300"
      xmlns:l="clr-namespace:MyNamespace">
     <UserControl.Resources>
      <l:ContainerWindowViewModel x:Key="containerWindowViewModel"/>
     </UserControl.Resources>
     <ContentPresenter DataContext="{Binding Source={StaticResource containerWindowViewModel}, Path=ChildControlViewModel}"
              Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type l:ContainerWindow}}, Path=ChildControl}" />
    </UserControl>

    If you have any problem, please feel free to let me know.

    Sincerely,

    Bob Bao


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Monday, June 14, 2010 5:48 AM
    Moderator
  • Is there a way to make this work with a data context that would not be created as a static resource by XAML?

    When I set a Data context binding in my ContentPresenter, the binding appears to be ignored.

    When I do the following:

    <ContentPresenter DataContext="{Binding ChildControlViewModel}"
         Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type l:ContainerWindow}}, Path=ChildControl}" />

    I get binding errors for my child control as it looks for the properties in the ContainerWindowViewModel instead of the ChildControlViewModel. If I remove the binding:

    <ContentPresenter
         Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type l:ContainerWindow}}, Path=ChildControl}" />

    I get the same result. So it is as if binding this way would do nothing in my code.


    -Sylvain
    Thursday, June 24, 2010 1:13 AM
  • Hi Sylvain,

    WPF Data Binding system will not try to find the path in the DataContext when the DataBinding has a explicit source:
      <ContentPresenter
         Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type l:ContainerWindow}}, Path=ChildControl}" />

    The code:
      
    <
    ContentPresenter DataContext="{Binding ChildControlViewModel}"
         Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type  l:ContainerWindow}}, Path=ChildControl}" />
    has a problem that the DataBinding {Binding ChildControlViewModel} will try to find the Path: ChildControlViewModel from ContentPresenter.DataContext and the parent control DataContext. But you do not sepcify the DataContext for the UserControl before, it throws an exception.

    Based on my understanding, the correct code you'd like is:

    <UserControl x:Class="MyNamespace.ContainerWindow"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     Height="300" Width="300"
     xmlns:l="clr-namespace:MyNamespace">
     <ContentPresenter DataContext="{Binding Path=ChildControlViewModel}"
         Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type l:ContainerWindow}}, Path=ChildControl}" />
    </UserControl>

    And in the behind code of the user control:

    ...
     InitializeComponent();
     ContainerWindowViewModel containerWindowViewModel = new ContainerWindowViewModel();
     containerWindowViewModel.ChildControlViewModel = ...;
     this.DataContext = containerWindowViewModel;
    
    ...

    Sincerely,

    Bob Bao


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Thursday, June 24, 2010 2:08 AM
    Moderator