Свойство DataContext FrameworkElement НЕ наследует дерево элементов - PullRequest
8 голосов
/ 19 декабря 2010

Здравствуйте, WPF Pro, по крайней мере, я надеюсь, что некоторые из вас читают это!

DataContext является свойством FrameworkElement (базовый класс для всех элементов управления WPF) и реализован в виде DependencyProperty.Это означает, что все элементы-потомки в логическом дереве совместно используют один и тот же DataContext.

Так что ContentControl должен делать это со своими элементами-потомками, верно?

У меня естьсценарий, где это НЕ дело, и я хотел бы знать, ЧТО является причиной такого неправильного поведения?!

Чтобы вы поняли немного больше об этом, пожалуйста, прочитайте эту ветку (НЕхочу скопировать все здесь), где начинается проблема ...:

WPF: Не удается найти цель триггера 'cc'.Цель должна появляться перед любыми сеттерами, триггерами

и говорить это в коротких словах : у моих DataTemplates в ContentControl действительно есть мертвый DataContext, что означает, что НИЧЕГО не нужно связывать сэто, что на самом деле невозможно ...

Каждый элемент в ContentControl не имеет НИЧЕГО установленного в свойстве DataContext ???

Ответы [ 4 ]

21 голосов
/ 19 декабря 2010

DataContext является собственностью на FrameworkElement (базовый класс для всех WPF Controls) и реализован как DependencyProperty. Это означает, что все элементы-потомки в логическом дерево разделяет один и тот же DataContext.

Тот факт, что это свойство зависимости не подразумевает наследование ... Это верно для DataContext, но только потому, что свойство зависимости имеет флаг FrameworkPropertyMetadataOptions.Inherits в своих метаданных.

Так что ContentControl должен это сделать с его потомками, верно?

ContentControl немного особенный: DataContext его потомков (визуальное дерево, построенное из DataTemplate) на самом деле является Content из ContentControl. Так что если у вашего ContentControl нет содержимого, DataContext внутри него будет нулевым.

13 голосов
/ 09 октября 2012

Это сработало для меня:

<ContentControl ContentTemplate="{StaticResource NotesTemplate}"
                Content="{Binding}"
                DataContext="{Binding HeightField}"/>

Без Content="{Binding}" DataContext был NULL

0 голосов
/ 04 сентября 2014

после прочтения этого вопроса и предыдущих ответов я предпочитаю использовать ContentControl с контентом, запускаемым данными:

Элементы управления, которые будут установлены как ContentControl:

<TextBox x:Key="ViewA">
   ...
</TextBox>
<ComboBox x:Key="ViewB">
   ...
</ComboBox>

ContentControl, который переключает собственный контент с помощью DataTrigger в стиле ContentControl:

<ContentControl>
  <ContentControl.Style>
    <Style>
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=Property}" Value="0">
                <Setter Property="Content" Value="{StaticResource ViewA}" />
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=Property}" Value="1">
                <Setter Property="Content" Value="{StaticResource ViewB}" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
  </ContentControl.Style>
</ContentControl>

Я надеюсь, что это поможет кому-то, как предыдущие ответы мне.

0 голосов
/ 04 декабря 2013

Последний ответ (от VinceF) работал и для меня.

Я хотел показать usercontrol в зависимости от значения свойства в моей viewmodel. Поэтому я сделал ContentControl с некоторыми триггерами стиля. В зависимости от значения свойства привязки триггер устанавливает конкретный шаблон содержимого, содержащий определенный пользовательский контроль.

Пользовательский контроль показывался правильно, но его DataContext всегда был нулевым. Поэтому мне пришлось установить Context of ContentControl на: Content="{Binding}" После этого UserControls работали нормально и имели тот же DataContext, что и их родительский элемент.

Итак, мой XAML выглядит так:

В части «Ресурсы» я определил два DataTemplates; каждый для каждого UserControl, который я хочу показать.

<DataTemplate x:Key="ViewA">
    <namespace:UserControlA/>
</DataTemplate>
<DataTemplate x:Key="ViewB">
    <namespace:UserControlB/>
</DataTemplate>

Часть, в которой я показываю UserControl в зависимости от свойства, выглядит следующим образом:

<ContentControl Content="{Binding}">
    <ContentControl.Style>
        <Style>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Property}" Value="0">
                    <Setter Property="ContentControl.ContentTemplate" Value="{StaticResource ViewA}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=Property}" Value="1">
                    <Setter Property="ContentControl.ContentTemplate" Value="{StaticResource ViewB}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>
</ContentControl>
...