代码之家  ›  专栏  ›  技术社区  ›  Rachel

WPF-TabControl和Zindex中重叠的自定义选项卡

  •  10
  • Rachel  · 技术社区  · 14 年前

    问题
    我有一个自定义选项卡控件,它使用了绑定到ViewModel的镀铬选项卡。由于形状的原因,边缘有点重叠。我有一个函数可以设置tabitem的zindex TabControl_SelectionChanged 这对于选择选项卡和拖放选项卡很有用,但是当我通过中继命令添加或关闭选项卡时,会得到异常的结果。有人有什么想法吗?

    默认视图:

    正在删除选项卡:

    在一行中添加2个或更多选项卡:

    一次添加超过1个选项卡不会重置其他最近添加的选项卡的zindex,因此它们位于右侧选项卡的后面,并且关闭选项卡不会正确呈现替换它的selectedtab的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设计模式,添加/关闭选项卡的按钮是中继命令。

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

    另外,我确实尝试在我的viewmodel中设置一个zindex并绑定到它,但是通过relay命令添加/删除选项卡时也会发生同样的事情。

    2 回复  |  直到 13 年前
        1
  •  5
  •   Rachel    14 年前

    谢谢你,亚伯,你的第二条评论让我找到了解决方案!

    我添加了 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)));
                    }
                }
            }
        }
    
        2
  •  1
  •   Abe Heidebrecht    14 年前

    听起来您只需要在集合更改时再次运行算法。因为你在测试 ItemContainerGenerator.Status 属性,算法可能无法运行。你可以考虑听 StatusChanged 事件,当它变为 ContainersGenerated 再次运行算法。