Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding in ContentControl Crash

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; }
like image 627
ImJames Avatar asked Dec 23 '10 14:12

ImJames


2 Answers

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; }
}
like image 155
John Bowen Avatar answered Oct 26 '22 21:10

John Bowen


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>
like image 20
Benlitz Avatar answered Oct 26 '22 22:10

Benlitz