Как выполнить привязку ContentTemplate к окружающему настраиваемому элементу управления?

У меня есть следующий пользовательский элемент управления:

<TabItem 
    x:Name = "Self"
    x:Class = "App.MyTabItem"
    xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:app = "clr-namespace:App"
    >
    <TabItem.Header>
        <!-- This works -->
        <TextBlock Text = "{Binding ElementName=Self, Path=ShortLabel, UpdateSourceTrigger=PropertyChanged}"/>
    </TabItem.Header>
    <TabItem.ContentTemplate>
        <DataTemplate>
            <!-- This binds to "Self" in the surrounding window's namespace -->
            <TextBlock Text = "{Binding ElementName=Self, Path=ShortLabel, UpdateSourceTrigger=PropertyChanged}"/>

Этот настраиваемый элемент TabItem определяет DependencyProperty 'ShortLabel' для реализации интерфейса. Я хотел бы выполнить привязку к этому и другим свойствам из TabItemDataTemplate. Но из-за странных взаимодействий TextBlock внутри DataTemplate привязывается к родительский контейнерTabItem, который также называется «Self», но определен в другом файле Xaml.

Вопрос

Почему привязка работает в TabItem.Header, но не из TabItem.ContentTemplate, и как мне перейти к свойствам пользовательского элемента управления из DataTemplate?

Что я уже пробовал

  • TemplateBinding: пытается выполнить привязку к ContentPresenter внутри TabItem.
  • FindAncestor, AncestorType = {x:Type TabItem}: не находит родительский элемент TabItem. Это тоже не работает, когда я указываю тип MyTabItem.
  • ElementName=Self: пытается выполнить привязку к элементу управления с таким именем в неправильной области (родительский контейнер, а не TabItem). Я думаю, это подсказывает, почему это не работает: DataTemplate создается не в точке, где он определен в XAML, а, по-видимому, родительским контейнером.

Я предполагаю, что могу заменить весь ControlTemplate, чтобы добиться желаемого эффекта, но, поскольку я хочу сохранить внешний вид TabItem по умолчанию без необходимости поддерживать весь ControlTemplate, я очень не хочу этого делать.

Редактировать

Тем временем я обнаружил, что проблема в следующем: TabControl не может иметь (любого) ItemsTemplate (включая DisplayMemberPath), если ItemsSource содержит Visual. Есть ветка на форуме MSDN, объясняющая, почему.

Поскольку это кажется фундаментальной проблемой с WPF TabControl, я закрываю вопрос. Спасибо за вашу помощь!

Дэвид Шмитт - может быть, лучше опубликовать найденную информацию в качестве ответа и принять ее? Потому что нет причин закрывать вопрос, а с ответом он может быть полезен.

MikroDel 26.11.2013 17:19

@MikroDel: Я не собираюсь отбирать репутацию за этот ответ. Вы можете публиковать и улучшать то, что я написал в разделе «Редактировать» в вопросе в качестве ответа. Это не меняет того факта, что WPF не поддерживает этот конкретный вариант использования.

David Schmitt 02.12.2013 12:56

Дело не в репутации для ответа. Ответ также может быть отрицательным - например, здесь «WPF не поддерживает ...». Я имею в виду, что другим пользователям будет легче найти информацию, если она будет размещена в качестве ответа, а не в вопросе.

MikroDel 02.12.2013 13:00

Вы можете опубликовать его как ответ и принять его. Я не хочу этого делать (опубликуйте ответ), потому что не нашел этой информации.

MikroDel 02.12.2013 13:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
4
17 025
2

Ответы 2

Попробуй это. Не уверен, сработает это или нет, но

<TabItem 
    x:Name = "Self"
    x:Class = "App.MyTabItem"
    xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:app = "clr-namespace:App"
    >
    <TabItem.ContentTemplate>
        <DataTemplate>
            <TextBlock Text = "{Binding Path=ShortLabel}"/>
        </DataTemplate>
    </TabItem.ContentTemplate>
</TabItem>

Если не работает, попробуйте вставить этот атрибут в <TabItem />:

DataContext = "{Binding RelativeSource = {RelativeSource self}}"

Проблема заключается в том, что вы используете ContentTemplate без фактического использования свойства content. DataContext по умолчанию для DataTemplate ContentTemplate - это свойство Content для TabItem. Однако ничто из того, что я сказал, на самом деле не объясняет Почему: привязка не работает. К сожалению, я не могу дать вам однозначного ответа, но я предполагаю, что это связано с тем, что TabControl повторно использует ContentPresenter для отображения свойства содержимого для всех элементов вкладки.

Итак, в вашем случае я бы изменил код, чтобы он выглядел примерно так:

<TabItem
    x:Class = "App.MyTabItem"
    xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:app = "clr-namespace:App"
    Header = "{Binding ShortLabel, RelativeSource = {RelativeSource Self}}"
    Content = "{Binding ShortLabel, RelativeSource = {RelativeSource Self}}" />

Если ShortLabel является более сложным объектом, а не просто строкой, вам следует ввести ContentTemplate:

<TabItem
    x:Class = "App.MyTabItem"
    xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:app = "clr-namespace:App"
    Header = "{Binding ShortLabel, RelativeSource = {RelativeSource Self}}"
    Content = "{Binding ComplexShortLabel, RelativeSource = {RelativeSource Self}}">
    <TabItem.ContentTemplate>
        <DataTemplate TargetType = "{x:Type ComplexType}">
            <TextBlock Text = "{Binding Property}" />
        </DataTemplate>
    </TabItem.ContentTemplate>
</TabItem>

Другие вопросы по теме