WPF - 在 TabControl 和 ZIndex 中重叠自定义选项卡 [英] WPF - Overlapping Custom Tabs in a TabControl and ZIndex

查看:33
本文介绍了WPF - 在 TabControl 和 ZIndex 中重叠自定义选项卡的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题
我有一个自定义选项卡控件,使用绑定到 ViewModel 的 Chrome 形状的选项卡.由于形状的原因,边缘有点重叠.我有一个函数可以在 TabControl_SelectionChanged 上设置 tabItem 的 ZIndex,它可以很好地选择选项卡和拖放选项卡,但是当我通过中继命令添加或关闭选项卡时,我得到了不寻常的结果.有人有什么想法吗?

Problem
I have a custom tab control using Chrome-shaped tabs that binds to a ViewModel. Because of the shape, the edges overlap a bit. I have a function that sets the tabItem's ZIndex on TabControl_SelectionChanged which works fine for selecting tabs, and dragging/dropping tabs, however when I Add or Close a tab via a Relay Command I am getting unusual results. Does anyone have any ideas?

默认视图:

删除标签:

连续添加 2 个或更多标签:

一次添加超过 1 个选项卡不会重置其他最近添加的选项卡的 zindex,因此它们位于右侧选项卡的后面,并且关闭选项卡不会正确呈现替换它的 SelectedTab 的 ZIndex,它显示在其右侧的标签后面.

Adding more then 1 tab at a time will not reset the zindex of other recently-added tabs so they go behind the tab on the Right, and closing tabs does not correctly render the ZIndex of the SelectedTab that replaces it and it shows up behind the tab on its right.

设置 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 设计模式,而添加/关闭选项卡的按钮是中继命令.

By using breakpoints I can see that it is correctly setting the ZIndex to what I want it to, however the layout is not displaying the changes. I know some of the changes are in effect because if none of them were working then the tab edges would be reversed (the right tabs would be drawn on top of the left ones). Clicking a tab will correctly set the zindex of all tabs (including the one that should be drawn on top) and dragging/dropping them to rearrange them also renders correctly (which removes and reinserts the tab item). The only difference I can think of is I am using the MVVM design pattern and the buttons that Add/Close tabs are relay commands.

有没有人知道为什么会发生这种情况以及我该如何解决?

Does anyone have any idea why this is happening and how I can fix it??

附言我确实尝试在我的 ViewModel 中设置 ZIndex 并绑定到它,但是通过中继命令添加/删除选项卡时会发生同样的事情.

p.s. I did try setting a ZIndex in my ViewModel and binding to it, however the same thing happens when adding/removing tabs via the relay command.

推荐答案

谢谢 Abe,你的第二条评论引导我找到我的解决方案!

Thank you Abe, your second comment lead me to my solution!

我在循环的每次迭代中添加了 tabItem.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);.

I added tabItem.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate); to each iteration of the loop.

我仍然有兴趣了解是否有人在每次更改时不刷新每个 tabItem 的情况下找到解决此问题的方法.我尝试在循环结束时刷新整个选项卡控件,但这仅适用于关闭选项卡,而不是添加它们.我知道 Panel.ZIndex 设置正确,只是在渲染时不尊重该属性.

I would still be interested in learning if anyone else finds a way around this without refreshing each tabItem on every change. I tried refreshing the entire tab control at the end of the loop but that only worked for closing tabs, not adding them. I know that Panel.ZIndex is getting set correctly, it's just not honoring that property when rendering.

当拖放选项卡时,上面的代码行会导致异常闪烁,这些选项卡会简要显示被拖动的选项卡后面的选项卡.我将代码移到一个单独的函数中,并以较低的调度程序优先级调用它,这解决了问题.最终代码如下:

The above line of code was causing an unusual flicker when Dragging/Dropping the tabs that would briefly show the tab behind the one being dragged. I moved the code to a separate function and called it at a lower dispatcher priority and this fixed the problem. Final code is below:

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)));
                }
            }
        }
    }

这篇关于WPF - 在 TabControl 和 ZIndex 中重叠自定义选项卡的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆