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

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

02.04.2026, 09:11. Показов 1675. Ответов 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
 Аватар для Элд Хасп
16154 / 11275 / 2890
Регистрация: 21.04.2018
Сообщений: 33,157
Записей в блоге: 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
Сообщений: 273
07.04.2026, 20:52  [ТС]
Элд Хасп, спасибо! это решило вопрос.
Объясните, пожалуйста, что такого изменило задать DataContext через ресурсы приложения? В чем такая разница как задан контекст?

Цитата Сообщение от Элд Хасп Посмотреть сообщение
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromPropert y(ItemsControl.ItemsSourceProperty, typeof(TabControl))
а почему вот тут надо получать именно от свойства ItemsSourceProperty?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16154 / 11275 / 2890
Регистрация: 21.04.2018
Сообщений: 33,157
Записей в блоге: 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
Сообщений: 273
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
Ответ Создать тему
Новые блоги и статьи
сукцессия 29. Переход от одних деревьев на другие делать более или менее вероятностным?
anaschu 12.07.2026
Насколько смена типов микоризы — исключительное событие в двухвековой сукцессии? Оценка вероятности в пространстве параметров В текущей версии модели успешно реализован ключевой механизм. . .
сукцессия 27. Думаю, как переделывать уже написанную статью с планами на сукцессию.
anaschu 12.07.2026
Анализ соответствия модели требованиям Реализованные компоненты: Механизм закисления почвы через протонную помпу Конкуренция между типами микориз pH как триггер сукцессии C/ P соотношение. . .
Сукцессия 26. Мат модель создана.
anaschu 12.07.2026
Модель смены растительных сукцессий посредством управления грибами работает внутри небольшой ячейки почвы, восстанавливающейся после пожара, где ненадолго бывшее царство хвойных снова захватили. . .
Решил проблему с ошибкой пагинации сообщений с сервера на алгоритме обхода дерева "Эстафета хвоста".
Hrethgir 12.07.2026
Проблема была в том, что удалялась именно новая кнопка, а не старая. Ни один ИИ не обнаружил это, а сам я смог только когда с работой стало попроще и когда заставил работать будущее автономное. . .
сукцессия 25. Хронология ошибок
anaschu 12.07.2026
# От 50-тонного гриба до устойчивого леса: хроника ошибок при построении модели вековой сукцессии микоризы ## О чём эта статья В процессе построения ОДУ-модели (система дифференциальных. . .
сукцессия 24. Промежуточное общее описание модели
anaschu 12.07.2026
Хендофф: модель АМ→ЭКМ сукцессии микоризы (ризосфера, 50 лет) Содержание проекта Симуляция вековой (50 лет) экологической сукцессии в почве леса Основные участники: АМ-гриб, ЭКМ-гриб,. . .
сукцессия 23. Более физиологичная физиология, более экологичная экология, более диффурные диффуры.
anaschu 12.07.2026
Что реально нашли и починили за эти 5 часов Правило Линдемана (КПД конверсии сахара в тело, kEff) — раньше 100% полученного углерода шло прямо в биомассу гриба; теперь только kEff=0. 5 (после. . .
сукцессия 22. От артефактов к физиологии: калибровка агентной модели грибной сукцессии для воспроизведения сезонной динамики и pH-плато
anaschu 11.07.2026
Аннотация В данной работе представлена калибровка агентной модели динамики грибных сообществ (fungal-succession), направленная на устранение нефизичных артефактов (коллапс биомассы, мгновенное. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru