ContentControl в UserControl вызывает исключение - PullRequest
0 голосов
/ 26 мая 2020

Добавление ContentControl с привязкой к моему UserControl вызывает исключение:

InvalidOperationException: Layout recursion reached allowed limit to avoid stack overflow: '2047'. Either the tree contains a loop or is too deep.

Я пытаюсь переключаться между двумя представлениями с использованием управления содержимым:

    <ContentControl Grid.Row="2" Content="{Binding}">
        <ContentControl.Style>
            <Style TargetType="ContentControl">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsListView}" Value="True">
                        <Setter Property="ContentTemplate" Value="{DynamicResource ListTemplate}" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding IsTabView}" Value="True">
                        <Setter Property="ContentTemplate" Value="{DynamicResource TabTemplate}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ContentControl.Style>
    </ContentControl>

После удаления Content={Binding} исключение исчезнет. Как я могу отследить источник исключения? Исследование членов исключения не дало никаких сведений о том, что может вызвать эту рекурсию.

UPD : оставление ContentControl пустым (например, без ListTemplate и TabTemplate) не означает не решает проблему.

1 Ответ

1 голос
/ 26 мая 2020

Проблема

ContentControl попытается показать, какое бы значение его свойства Content ни использовало ContentPresenter. MSDN do c, которую я привел, описывает полный logi c, который ContentPresenter использует для определения того, как лучше всего отображать предоставленный контент, но это два наиболее важных момента:

Сначала он попробует следующее:

  • Если свойство ContentTemplate в ContentPresenter установлено, ContentPresenter применяет это DataTemplate к свойству Content и в результате Отображаются UIElement и его дочерние элементы, если таковые имеются.

Позже, если вышеуказанное не удалось (то есть ContentTemplate не было установлено), он попробует следующее:

  • Если Content - это объект UIElement, отображается UIElement. Если у UIElement уже есть родительский элемент, возникает исключение.

Когда вы впервые загружаете ContentControl, Content="{Binding}" устанавливает Content в DataContext, что я ' м предполагая, что это ваш UserControl. Ваш Style имеет триггеры, которые устанавливают ContentTemplate условно . Это означает, что будут моменты, когда ContentTemplate = не установлено , поэтому ContentPresenter по умолчанию будет пытаться отобразить Content, который является UIElement, в качестве одного из его дочерних элементов.

Таким образом, ContentPresenter попытается отобразить весь UserControl как его дочерний элемент, без проблем, за исключением того, что часть этого нового «дочернего элемента» является самим собой, поэтому для рендеринга своей внутренней версии ему необходимо отобразить Content свойство. И так продолжается в бесконечном рекурсивном l oop из ContentControl s, пытающихся отобразить себя внутри себя, пока не будет достигнут предел, и WPF откажется и выдаст исключение.

Решение

  1. Всегда имейте ContentTemplate. Вам понадобится какое-то значение по умолчанию ContentTemplate для ContentControl, чтобы показать, не сработал ли ни один из триггеров.

  2. Используйте ContentPresenter напрямую вместо ContentControl Я не совсем уверен, почему это так, но даже после предоставления значения по умолчанию ContentTemplate это все равно не сработает. Вероятно, это как-то связано с внутренней работой ContentControl. Однако замена ContentControl на ContentPresenter исправляет все.

<ContentPresenter Grid.Row="2" Content="{Binding}">
    <ContentPresenter.Style>
        <Style TargetType="ContentPresenter">
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <!--"Default" template that will be used if none of the triggers are active-->
                    <DataTemplate>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
                    
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsListView}" Value="True">
                    <Setter Property="ContentTemplate" Value="{DynamicResource ListTemplate}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding IsTabView}" Value="True">
                    <Setter Property="ContentTemplate" Value="{DynamicResource TabTemplate}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentPresenter.Style>
</ContentPresenter>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...