Как привязать элемент управления tab извне к элементу управления tab при использовании ControlTemplates?

#wpf

#wpf

Вопрос:

Я хочу привязать внешний элемент управления tab к его внутренней части. В принципе, это работает до тех пор, пока, но когда я использую ContentTemplate, я понятия не имею, как обратиться к цели привязки.

Приведенный ниже код содержит две пары TextBlock и TabItem. Первый блок работает, второй, использующий ContentTemplate, — нет.

 <Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    
    <TextBlock 
        Grid.Row="0"
        Text="{Binding ElementName=redTtextBlock, Path=Text}" 
        Foreground="Red"
        />

    <TabControl Grid.Row="1">
        <TabItem 
            Header="Red header"
            >
            <TextBlock 
                    x:Name="redTtextBlock"
                    Text="Red text"
                    Foreground="Red"
                    />
        </TabItem>
    </TabControl>
    
    <TextBlock 
        Grid.Row="2"
        Text="{Binding ElementName=greenTtextBlock, Path=Text}" 
        Foreground="Olive"
        />

    <TabControl Grid.Row="3">
        <TabControl.Resources>
            <DataTemplate x:Key="template" DataType="TabItem">
                <TextBlock 
                    x:Name="greenTtextBlock"
                    Text="Green text"
                    Foreground="Olive"
                    />
            </DataTemplate>
        </TabControl.Resources>
            <TabItem 
                Header="Green header"
                ContentTemplate="{StaticResource template}">
        </TabItem>
    </TabControl>

</Grid>
  

Комментарии:

1. Вы не можете привязаться к фактическому, TextBlock созданному DataTemplate . Вы должны привязать оба TextBlocks к общему свойству исходного кода.

2. Спасибо mm8. Хороший вариант обойти это ограничение. Но могу я спросить об этом; Откуда я мог знать? Есть ли объяснение, когда можно привязываться к элементам вместе, а когда нет? Меня удивляет, что эта привязка невозможна напрямую.

Ответ №1:

Вы никогда не сможете привязать внешний элемент любого шаблона к его внутренней части. Это совершенно разные области.

«Откуда я мог знать? Есть ли объяснение, когда можно привязываться к элементам вместе, а когда нет? Меня удивляет, что эта привязка невозможна напрямую.»

Вы не должны удивляться. Если вы понимаете, как работают шаблоны, то вы бы знали, что вторая привязка не может работать.
Первый пример привязки к элементу управления, где цель привязки и источник имеют общую область имен. Шаблон, например, DataTemplate или ControlTemplate , всегда имеет свой собственный namescope, поскольку он описывает динамическое визуальное поддерево.

Подумайте об этом: a DataTemplate , который определяется как шаблон элемента a ItemsControl и содержит элемент с именем «TemplateElement», применяется к каждому элементу этого ItemsControl .
Если бы шаблон не определял свою собственную изолированную область имен, тогда было бы несколько элементов с одинаковым именем — в одной области имен. Делая вид, что это законно, как выражение привязки может «знать», какой из повторяющихся элементов привязка использует в качестве своего источника? Они являются дубликатами с точки зрения именования, но уникальны в отношении их содержимого. Это должно дать понять, что это никогда не сможет сработать.

DataTemplate Это не элемент. Это схема построения для нескольких элементов. Из-за этого множества невозможно привязать элемент шаблона извне к элементу этого шаблона. То же самое относится к ControlTemplate .

Кроме того, и это самое важное, шаблоны являются частью визуального дерева, но не логического дерева. Помимо области имен в случае Binding.ElementName , это основная причина, по которой Binding , определенный вне шаблона, не может разрешить источник, если сам источник является частью шаблона. Binding.RelativeSource выражения пересекают только логическое дерево. Это означает, что Binding никогда не сможет найти внутренние элементы составного элемента (визуальное дерево), а только прямые элементы верхнего уровня (логическое дерево).

Комментарии:

1. Большое спасибо BioncCode. Я многому научился! Однако, если я правильно помню, TabControl каким-то образом является особенным, поскольку у него есть только одно визуальное дерево для всех элементов, не так ли?

2. TabControl является гибридом ItemsControl и ContentControl . В нем есть элементы, TabItem elements. TabItem Имеет заголовок TabItem.Content , который создается с помощью шаблона TabControl.ItemTemplate . Все заголовки всегда видны. И TabItem имеет содержимое TabControl.SelectedContent , которое создается по шаблону через TabControl.ContentTemplate . Отображается только одно содержимое, содержимое TabControl.SelectedItem .

3. Все элементы tab совместно используют один узел содержимого, который отображает фактическое содержимое выбранного в данный момент элемента TabItem , значение TabControl.SelectedContent . Как вы можете видеть из квалификатора свойства, узел содержимого является не частью TabItem , а частью TabControl самого. Это означает, что, хотя у каждого элемента есть свое собственное визуальное (вложенное) дерево для описания их заголовков, существует только одно визуальное (вложенное) дерево, которое описывает содержимое. Содержимое каждой вкладки меняется местами.

4. Прохладный. Еще раз спасибо.