10

问题
我有一个自定义选项卡控件,它使用绑定到 ViewModel 的 Chrome 形选项卡。由于形状的原因,边缘有点重叠。我有一个函数可以设置 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 设计模式,而添加/关闭选项卡的按钮是中继命令。

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

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

4

2 回答 2

5

谢谢Abe,您的第二条评论使我找到了解决方案!

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

我仍然有兴趣了解是否有其他人找到解决此问题的方法,而无需在每次更改时刷新每个 tabItem。我尝试在循环结束时刷新整个选项卡控件,但这仅适用于关闭选项卡,而不是添加它们。我知道 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)));
                }
            }
        }
    }
于 2010-03-30T19:49:10.760 回答
1

听起来您只需要在集合更改时再次运行您的算法。由于您正在测试该ItemContainerGenerator.Status属性,因此该算法可能无法运行。您可能需要考虑监听StatusChanged事件,并在它发生变化时ContainersGenerated再次运行算法。

于 2010-03-26T19:54:31.497 回答