WPF - перекрывающиеся пользовательские вкладки в TabControl и ZIndex

Задача
У меня есть пользовательский элемент управления вкладками, использующий вкладки в форме Chrome, которые привязываются к ViewModel. Из-за формы края немного перекрываются. У меня есть функция, которая устанавливает ZIndex tabItem на TabControl_SelectionChanged, которая отлично работает для выбора вкладок и перетаскивания вкладок, однако когда я добавляю или закрываю вкладку с помощью команды ретрансляции, я получаю необычные результаты. У кого-нибудь есть идеи?

Вид по умолчанию:

Удаление вкладок:

Добавление 2 или более вкладок в ряд:

Добавление более чем одна вкладка за раз не будет сбрасывать zindex других недавно добавленных вкладок, поэтому они переходят за вкладку справа, а закрытие вкладок неправильно отображает ZIndex выбранной вкладки, которая заменяет ее, и отображается за вкладкой справа от него.

Код для установки ZIndex

private void PrimaryTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.Source is TabControl)
        {
            TabControl tabControl = sender as TabControl;
            ItemContainerGenerator icg = tabControl.ItemContainerGenerator;
            if (icg.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
            {
                foreach (object o in tabControl.Items)
                {
                    UIElement tabItem = icg.ContainerFromItem(o) as UIElement;
                    Panel.SetZIndex(tabItem, (o == tabControl.SelectedItem ? 100 :
                        90 - tabControl.Items.IndexOf(o)));
                }
            }
        }
    }

Используя точки останова, я вижу, что он правильно устанавливает ZIndex на то, что я хочу, однако макет не отображает изменения. Я знаю, что некоторые изменения вступили в силу, потому что если бы ни одно из них не работало, то края вкладок были бы перевернуты (правые вкладки были бы нарисованы поверх левых). Нажатие на вкладку правильно установит zindex всех вкладок (включая ту, которая должна быть нарисована сверху), а перетаскивание их для изменения их порядка также правильно отображает (что удаляет и повторно вставляет элемент вкладки). Единственное отличие, о котором я могу подумать, это то, что я использую шаблон проектирования MVVM, а кнопки, которые вкладки Add / Close - это команды реле.

Кто-нибудь знает, почему это происходит и как я могу это исправить?

с. Я попытался установить ZIndex в моей ViewModel и привязать его, однако то же самое происходит при добавлении / удалении вкладок с помощью команды relay.

10
задан Community 8 February 2017 в 14:23
поделиться

2 ответа

Спасибо, Эйб, твой второй комментарий привел меня к моему решению!

Я добавил tabItem.Dispatcher.Invoke (DispatcherPriority.Render, EmptyDelegate); на каждую итерацию цикла.

Мне все равно было бы интересно узнать, найдет ли кто-нибудь способ обойти это, не обновляя каждый элемент вкладки при каждом изменении.Я попытался обновить весь элемент управления вкладками в конце цикла, но это сработало только для закрытия вкладок, а не для их добавления. Я знаю, что Panel.ZIndex устанавливается правильно, он просто не учитывает это свойство при рендеринге.

РЕДАКТИРОВАТЬ: Вышеупомянутая строка кода вызывала необычное мерцание при перетаскивании вкладок, которое на короткое время показывало вкладку за перетаскиваемой. Я переместил код в отдельную функцию и вызвал ее с более низким приоритетом диспетчера, и это устранило проблему. Окончательный код приведен ниже:

private void PrimaryTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.Source is TabControl)
        {
            TabControl tabControl = sender as TabControl;

            tabControl.Dispatcher.BeginInvoke(
                new Action(() => UpdateZIndex(sender as TabControl)),
                DispatcherPriority.Background);
        }
    }

    private void UpdateZIndex(TabControl tabControl)
    {
        ItemContainerGenerator icg = tabControl.ItemContainerGenerator;

        if (icg.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
        {
            foreach (object o in tabControl.Items)
            {
                UIElement tabItem = icg.ContainerFromItem(o) as UIElement;
                if (tabItem != null)
                {
                    // Set ZIndex
                    Panel.SetZIndex(tabItem, (o == tabControl.SelectedItem ? 100 :
                        90 - tabControl.Items.IndexOf(o)));
                }
            }
        }
    }
5
ответ дан 4 December 2019 в 03:16
поделиться

Похоже, вам просто нужно снова запустить свой алгоритм при изменении коллекции. Поскольку вы тестируете ItemContainerGenerator.Status , алгоритм может не работать. Вы можете рассмотреть возможность прослушивания события StatusChanged , и когда оно изменится на ContainersGenerated , запустите алгоритм снова рифм.

1
ответ дан 4 December 2019 в 03:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: