Binding in ContentControl Crash
Asked Answered
A

3

13

Can anyone tell me why this crashes my app? There seems to be some endless recursion by I can't figure out why. I get this exception

Logical tree depth exceeded while traversing the tree. This could indicate a cycle in the tree

<ContentControl Content="{Binding}">
    <ContentControl.ContentTemplate>
        <DataTemplate>
            <Button Content="{Binding MyString}"/>
        </DataTemplate>
    </ContentControl.ContentTemplate>
</ContentControl>

And this is all I have as Source

    public MainWindow()
    {
        InitializeComponent();
        MyString = "Test";
        this.DataContext = this;
    }

    public string MyString { get; set; }
Abstergent answered 23/12, 2010 at 14:48 Comment(0)
L
20

You're using MainWindow as the DataContext of the MainWindow's content. When you set Content="{Binding}" on the ContentControl this is setting the ContentControl's content to the MainWindow instance. This is a problem because the ContentControl is contained in the MainWindow's Content. Whenever a Content property receives a UIElement, it renders it as a UIElement, not through the DataTemplate as it would with an non-UI class. So your tree ends up being

MainWindow
 ContentControl
  MainWindow
   ContentControl
    ...

Using a separate data object for your DataContext instead of the window itself will give you the behavior you're looking for:

public partial class Window13 : Window
{
    public Window13()
    {
        InitializeComponent();
        MyData data = new MyData();
        data.MyString = "Test";
        this.DataContext = data;
    }
}

public class MyData
{
    public string MyString { get; set; }
}
Lammers answered 23/12, 2010 at 19:21 Comment(1)
John, you're the man!! Works like a charm :) I can finally put this problem behind me and I also know the reason thanks to your very clear explanation! Thanks and merry christmasAbstergent
P
3

Although I totally agree with the accepted answer that you should not do this, sometimes you just don't have the choice. For instance, I'm using Xceed PropertyGrid and the DataContext I have for each item of the grid is a PropertyItem which is a UIElement (containing the actual data in a Value member).

The workaround I found is to use a ContentPresenter instead of a ContentControl. The documentation is not clear about this but it seems that UIElement are templated instead of being used as-is.

<ContentPresenter Content="{Binding}">
    <ContentPresenter.ContentTemplate>
        <DataTemplate>
            <Button Content="{Binding MyString}"/>
        </DataTemplate>
    </ContentPresenter.ContentTemplate>
</ContentPresenter>
Protolithic answered 5/12, 2013 at 10:19 Comment(0)
O
0

You should remove the binding on the Content property of the ContentControl. What is this supposed to do anyway?

Office answered 23/12, 2010 at 15:5 Comment(1)
My understand of the ContentControl is that the DataContext within the DataTemplate is the Content of the ContentControl and not the DataContext. So if I remove it I don't get a DataContext within the DataTemplate to bind to at all. Any ideas?Abstergent

© 2022 - 2024 — McMap. All rights reserved.