Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
3 / 3 / 0
Регистрация: 23.12.2016
Сообщений: 278

Почему у ContentControl не срабатывает триггер на событие DataContextChanged

02.04.2026, 09:11. Показов 2186. Ответов 23

Студворк — интернет-сервис помощи студентам
Здравствуйте.
Происходит что-то непонятное. У меня есть основное окно в ней TabControl, вкладки создаются динамически, содержимое вкладок практически идентичное, отличается только основной контрол для отображения данных. Создал UserControl который содержит ContentControl для отображения этих отличающихся данных. Мне надо чтоб при переходе по вкладкам (и при первом открытии окна и первой вкладки) происходила загрузка данных из базы.
Попробовал сделать так:
XML
1
2
3
4
5
6
7
8
9
<ContentControl Grid.Row="0" 
                Content="{Binding}">
 
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="DataContextChanged">
            <b:InvokeCommandAction Command="{Binding LoadDataCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
        </b:EventTrigger>
    </b:Interaction.Triggers>
</ContentControl>
И это не работает в команду я не попадаю. Но если сделаю через обычный обработчик в коде UserControl, то при переходе по вкладкам событие срабатывает.
XML
1
DataContextChanged="ContentControl_DataContextChanged"
Почему обычный обработчик события срабатывает а триггер нет?
Xaml UserControl:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
 
    <ContentControl Grid.Row="0" 
                    Content="{Binding}">
 
        <b:Interaction.Triggers>
            <b:EventTrigger EventName="DataContextChanged">
                <b:InvokeCommandAction Command="{Binding LoadDataCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
            </b:EventTrigger>
        </b:Interaction.Triggers>
    </ContentControl>
 
    <StackPanel Orientation="Horizontal"
                Grid.Row="1">
 
        <CheckBox Margin="5"
                  VerticalAlignment="Center"
                  Command="{Binding SetChoiceAllCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
                  CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}">
 
            <CheckBox.Style>
                <Style TargetType="CheckBox">
 
                    <Setter Property="Content" Value="Выбрать все"/>
 
                    <Style.Triggers>
 
                        <DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource Self}}" Value="True">
                            <Setter Property="Content" Value="Снять все"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </CheckBox.Style>
        </CheckBox>
 
        <Button Content="{Binding ButtonText, RelativeSource={RelativeSource AncestorType=UserControl}}"
                Margin="15,5,5,5"
                Padding="10"
                Height="40"
                Style="{StaticResource CornerButtonStyle}"
                Command="{Binding ExecuteActionCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
    </StackPanel>
</Grid>
Код за кулисами:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public partial class TabItemControl : UserControl
{
    public TabItemControl()
    {
        InitializeComponent();
    }
 
    #region Свойство зависимости для подписки на команду "Выбрать все"
 
    public static readonly DependencyProperty SetChoiceAllCommandProperty =
        DependencyProperty.Register("SetChoiceAllCommand", typeof(ICommand), typeof(TabItemControl));
 
    public ICommand SetChoiceAllCommand
    {
        get => (ICommand)GetValue(SetChoiceAllCommandProperty);
        set => SetValue(SetChoiceAllCommandProperty, value);
    }
 
    #endregion
 
    #region Свойство зависимости для подписки на команду "Загрузить данные"
 
    public static readonly DependencyProperty LoadDataCommandProperty =
        DependencyProperty.Register("LoadDataCommand", typeof(ICommand), typeof(TabItemControl));
 
    public ICommand LoadDataCommand
    {
        get => (ICommand)GetValue(LoadDataCommandProperty);
        set => SetValue(LoadDataCommandProperty, value);
    }
 
    #endregion
 
    #region Свойство зависимости для установки текста кнопки
 
    public static readonly DependencyProperty ButtonTextProperty =
        DependencyProperty.Register("ButtonText", typeof(string), typeof(TabItemControl));
 
    public string ButtonText
    {
        get => (string)GetValue(ButtonTextProperty); 
        set => SetValue(ButtonTextProperty, value);
    }
 
    #endregion
 
    #region Свойство зависимости для подписки на команду "Выполнить действие" (для кнопки)
 
    public static readonly DependencyProperty ExecuteActionCommandProperty =
        DependencyProperty.Register("ExecuteActionCommand", typeof(ICommand), typeof(TabItemControl));
 
    public ICommand ExecuteActionCommand
    {
        get => (ICommand)GetValue(ExecuteActionCommandProperty);
        set => SetValue(ExecuteActionCommandProperty, value);
    }
 
    #endregion
 
    //private void ContentControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    //{
 
    //}
}
в главной VM есть коллекция vm для каждой TabItem:
C#
1
2
3
4
5
public ObservableCollection<BaseTabViewModel> TabViewModels
{
    get => _tabViewModels;
    set { _tabViewModels = value; OnPropertyChanged(); }
}
В главном окне также сделал 2 DataTemplate для каждого типа vm для отображения данных. Вот так создаю TabControl:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<TabControl Grid.Row="0"
            Margin="0,5,0,0"
            BorderBrush="Black"
            BorderThickness="0.5"
            ItemsSource="{Binding TabViewModels}"
            SelectedIndex="0">
    
    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Title}"/>
        </DataTemplate>
    </TabControl.ItemTemplate>
 
    <TabControl.ContentTemplate>
        <DataTemplate>
            <customControls:TabItemControl DataContext="{Binding}" 
                                           LoadDataCommand="{Binding LoadDataCommand}"
                                           SetChoiceAllCommand="{Binding SetChoiceAllCommand}"
                                           ButtonText="{Binding ButtonText}"
                                           ExecuteActionCommand="{Binding ExecuteActionCommand}"/>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>
Что не так почему триггер из Microsoft.Xaml.Behaviors.Wpf не срабатывает? DataContext точно меняется проверил в дебаге и обработчик события это доказал.

Попробовал через обработчик события вызывать команду и видимо мой вариант не подходит, при первом попадании команда null и ничего не происходит, а при переходе на другую вкладку вызывается команда из первой TabVM, хотя должна вызываться из второй.
Может быть надо это делать на уровне TabControl, но там не получилось добавить команду для загрузки данных
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
02.04.2026, 09:11
Ответы с готовыми решениями:

Обработка DataContextChanged через команды
Хочу задать фильтры отображения данных через команду. На данный момент выполнено вот так : ...

Освобождение памяти при очистке ContentControl
Добрый день! Ситуация следующая, динамически создаю некотрый userControl, помещаю его в...

Создание динамической привязки с ContentControl
Имеется ContentControl (являет собою контейнер для элемента диаграммы). Необходимо привязать к...

23
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16445 / 11288 / 2892
Регистрация: 21.04.2018
Сообщений: 33,185
Записей в блоге: 2
07.04.2026, 20:23
Лучший ответ Сообщение было отмечено IIIIIIIIIgor как решение

Решение

Студворк — интернет-сервис помощи студентам
Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
Вот проект в архиве.
C#
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
 
            var brokenVersionTreesVM = new BrokenVersionTreesViewModel();
            var objectsToRreplaceVersionsVM = new ObjectsToRreplaceVersionsViewModel();
            Resources["vm"] = new MainViewModel(brokenVersionTreesVM, objectsToRreplaceVersionsVM);
 
            var window = new MainWindow();
            //window.DataContext = new MainViewModel(brokenVersionTreesVM, objectsToRreplaceVersionsVM);
 
            window.Show();
        }
    }
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<Window x:Class="TestTabControl.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestTabControl.Views"
        xmlns:vm="clr-namespace:TestTabControl.ViewModels"
        xmlns:customControls="clr-namespace:TestTabControl.CustomControls"
        xmlns:models="clr-namespace:TestTabControl.Models"
        xmlns:viewObjects="clr-namespace:TestTabControl.ViewObjects"
        d:DataContext="{d:DesignInstance vm:MainViewModel}"
        DataContext="{DynamicResource vm}"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
Добавлено через 11 минут
Ну, или оставить как есть и подключить выбор индекса после изменения ItemsSource:
C#
11
12
13
14
15
16
17
18
19
20
21
22
23
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
 
            DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof(TabControl))!;
            dpd.AddValueChanged(tbCtrl, async (s, e) =>
                {
                    await tbCtrl.Dispatcher.BeginInvoke(new Action(() => tbCtrl.SelectedIndex = 0));
                });
        }
    }
1
3 / 3 / 0
Регистрация: 23.12.2016
Сообщений: 278
07.04.2026, 20:52  [ТС]
Элд Хасп, спасибо! это решило вопрос.
Объясните, пожалуйста, что такого изменило задать DataContext через ресурсы приложения? В чем такая разница как задан контекст?

Цитата Сообщение от Элд Хасп Посмотреть сообщение
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromPropert y(ItemsControl.ItemsSourceProperty, typeof(TabControl))
а почему вот тут надо получать именно от свойства ItemsSourceProperty?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16445 / 11288 / 2892
Регистрация: 21.04.2018
Сообщений: 33,185
Записей в блоге: 2
08.04.2026, 01:46
Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
Объясните, пожалуйста, что такого изменило задать DataContext через ресурсы приложения? В чем такая разница как задан контекст?
Инициализация XAML происходит в методе InitializeComponent();.
В вашем коде, на момент выполнения этого метода, ещё нет Контекста Данных и значит ItemsSource="{Binding TabViewModels}"=null. В этом случае задание индекса SelectedIndex="0" не срабатывает, так как коллекции ещё нет. А когда он не срабатывает, то SelectedIndex принимает значение -1.
После инициализации XAML вы задаёте контекст данных. Но к этому времени SelectedIndex=-1 и SelectedItem="{Binding SelectedTab}" в ViewModel тоже null. И TabControl, естественно, остаётся в невыбранном состоянии.

В моём коде ViewModel создаётся до создания окна. В окне контекст данных тянется динамическим ресурсом DataContext="{DynamicResource vm}" поэтому на момент инициализации TebControl уже есть значение для его ItemsSorce и, соответственно, SelectedIndex="0" приводит к выбору элемента коллекции, который передаётся в ViewModel через привязку SelectedItem="{Binding SelectedTab}".

Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
Цитата Сообщение от Элд Хасп Посмотреть сообщение
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromPropert y(ItemsControl.ItemsSourceProperty, typeof(TabControl))
а почему вот тут надо получать именно от свойства ItemsSourceProperty?
Эта логика приводит к автоматическому выбору первого элемента коллекции при смене коллекции в свойстве ItemsSource.
Такой универсальный вариант, который всегда сработает. Если коллекция не будет меняться, как у вас, сработает только один раз. И дальше мешать не будет.
Можно конечно прослушивать DataContext, но здесь будет неочевидная логика. Ведь необязательно же смена контекста данных приведёт к смене коллекции, и необязательно что коллекция будет меняться только одновременно со сменной контекста данных.
Поэтому и решил, что так будет оптимальнее и логичнее.
1
3 / 3 / 0
Регистрация: 23.12.2016
Сообщений: 278
08.04.2026, 08:34  [ТС]
Элд Хасп, спасибо за помощь и объяснения
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
08.04.2026, 08:34

ControlTemplate и ContentControl: как динамически загрузить шаблон?
В ContentControl в свойство Template устанавливаю ранее созданный шаблон (ControlTemplate)...

Зависимость Ellipse от Rectangle(ContentControl)
Есть задача, создать переключатель(switch). Но чтобы он был настраиваемым из View: &lt;Grid&gt; ...

System.Windows.Controls.ContentControl
System.Windows.Controls.ContentControl. Это базовый класс для всех элементов управления, которые...

Не работает привязка ContentControl
Пытался создать программу, взяв за основу проект &quot;Штатное Расписание&quot; от Элд Хасп. Есть словарь: ...

Не все ContentControl отображаются в ItemsControl
Здравствуйте, уважаемые! Уже не знаю где смотреть, да и как вопрос толком задать - не очень...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
24
Ответ Создать тему
Новые блоги и статьи
Про "Windows must die!"
kumehtar 04.11.2026
Знаете, чет накатило. . . . Когда-то это было почти боевым кличем: мол, нормальный человек сидит на DOS, OS/ 2 или Linux, а вот это вот - Must Die. А теперь человек произносит «мастдай» с усмешкой - и. . .
Красочные поля с номером страницы svg+background-image
russiannick 04.11.2026
Красочные поля с номером страницы не менее важны чем в эпоху бумажных книг. Посему спешу представить почтеннейшей публике этот важный инструмент который эти поля и формирует. В процессе разработки. . .
Вступаем в новую фазу генерации favicons, векторную.
russiannick 02.11.2026
Теперь нет нужды скрывать что используется простой svg. Исходный код изображения помещаем в поле и жмем кнопку. Исходник преобразуется в вид корректный для помещения в favicon или в url(). Нажатие. . .
Генератор паролей (вариант №4)
Maks 01.11.2026
После публикации 3-го варианта генератора паролей, разослал его своим коллегам (с целью оценки), в итоге были получены следующие рекомендации: 1. Вернуть возможность использования знаков | 1 l I;. . .
Генератор паролей (вариант №3)
Maks 30.10.2026
Финальная версия генератора паролей 1С. Доработка решения в этот раз коснулась только визуальной части, а именно, добавлен реквизит ДопПараметры (тип Булево), который скрывает/ отображает реквизиты:. . .
Магическое мышление и магия, современная наука не отличима от магии (говорит ИИ Джемени)
zorxor 30.10.2026
Джемени, расскажи, пожалуйста, что такое магическое мышление, что такое магия, почему современная наука чем-то напоминает магию? Фраза «Любая достаточно развитая технология неотличима от магии». . .
За какое время ИИ может подобрать пароль по хешу (рассказывает Джемени ИИ)
zorxor 30.10.2026
Расскажи, Джемени, если известен хэш МД5, например, за сколько ИИ сможет подобрать соответствующий пароль? Искусственный интеллект (ИИ) может подобрать простой или средний по сложности пароль по. . .
Кто убил Suno? Почему наше солнышко погасло? (диалог с ИИ Джемени)
zorxor 30.10.2026
Как убивали Suno. Хронология. «Убийство» музыкальной нейросети Suno — это затяжной процесс, в котором технологический хайп стартапа разбился о жесткую реальность судебных исков от гигантов. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru