WPF-TabControl和ZIndex中重叠的自定义选项卡
问题WPF-TabControl和ZIndex中重叠的自定义选项卡,wpf,tabcontrol,z-index,tabitem,Wpf,Tabcontrol,Z Index,Tabitem,问题 我有一个自定义选项卡控件,它使用绑定到ViewModel的镀铬选项卡。由于形状的原因,边缘有点重叠。我有一个函数,可以在TabControl\u SelectionChanged上设置tabItem的ZIndex,该函数可以很好地用于选择选项卡和拖放选项卡,但是当我通过中继命令添加或关闭选项卡时,我会得到不寻常的结果。有人有什么想法吗 默认视图: 删除选项卡: 在行中添加两个或更多选项卡: 一次添加多个选项卡不会重置其他最近添加的选项卡的zindex,因此它们会位于右侧选项卡的后面,
我有一个自定义选项卡控件,它使用绑定到ViewModel的镀铬选项卡。由于形状的原因,边缘有点重叠。我有一个函数,可以在
TabControl\u SelectionChanged
上设置tabItem的ZIndex,该函数可以很好地用于选择选项卡和拖放选项卡,但是当我通过中继命令添加或关闭选项卡时,我会得到不寻常的结果。有人有什么想法吗
默认视图:删除选项卡:
在行中添加两个或更多选项卡:
一次添加多个选项卡不会重置其他最近添加的选项卡的zindex,因此它们会位于右侧选项卡的后面,关闭选项卡不会正确呈现替换它的选定选项卡的zindex,它会显示在右侧选项卡的后面 设置ZIndex的代码
通过使用断点,我可以看到它正确地将ZIndex设置为我想要的,但是布局没有显示更改。我知道有些更改是有效的,因为如果它们都不起作用,则选项卡边缘将反转(右选项卡将绘制在左选项卡的顶部)。单击某个选项卡将正确设置所有选项卡(包括应在顶部绘制的选项卡)的zindex,并通过拖放这些选项卡来重新排列它们,从而正确渲染(这将删除并重新插入选项卡项)。我能想到的唯一区别是我使用的是MVVM设计模式,添加/关闭选项卡的按钮是中继命令 有没有人知道为什么会发生这种情况,以及我如何解决它
p、 我确实尝试在我的ViewModel中设置一个ZIndex并绑定到它,但是当通过relay命令添加/删除选项卡时也会发生同样的情况。听起来,当集合发生变化时,您只需要再次运行算法。由于您正在测试
ItemContainerGenerator.Status
属性,因此算法可能无法运行。你可能想考虑听<代码> StasuSuffs事件,当它改变为<代码>容器生成的< /代码>再次运行算法。 < P>谢谢Abe,你的第二个评论引导我找到了解决方案!p>
我添加了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)));
}
}
}
}
我已经试过了,但仍然没有正确显示。此外,ItemContainerGenerator.StatusChanged事件在更新SelectedItem之前运行,因此设置它时始终将选定选项卡设置为最后选定的选项卡。通过使用断点,我可以看到Panel.ZIndex在使用TabControl_SelectionChanged事件添加/删除选项卡时确实设置正确,但是它没有按应有的方式绘制它们。对我来说,这是没有意义的,因为拖放标签(同时删除和重新添加tabItem)正确地绘制了标签顺序。是的,这很奇怪。我能想到的d&d和仅仅添加一个新项之间的唯一区别是z-index算法运行的时间。也许在调度器上以较低的优先级调用它(如DispatcherPriority.Input)将是一个(hacky)解决方案。我现在认为这是WPF的问题,而不是我的代码的问题。我添加了一个按钮,显示了选项卡项在绘制后的zIndex,所有选项卡项的zIndex都是正确的,只是没有正确绘制。您好。在WPF中,给TabControl中的tab赋予类似于铬的梯形形状,并让它们正确地工作似乎是相当棘手的。您是否有机会分享用于模板/样式设置的XAML?我这里有一个解决方案,但它不是特别优雅-好奇你做了什么!干杯。当然,代码有点太长,不能在这里发布,但我会尽力解释。如果您有任何问题,请随时发电子邮件给我rlim@email.itt-技术教育。每个选项卡实际上是一个包含3个单元格的网格-左侧和右侧的单元格包含绘制曲线的路径,中间的单元格包含数据。每个网格都有一个负边距集以使它们重叠,zIndex用于设置哪个网格应该位于顶部。不确定是否要添加拖放或滚动,但在我的例子中,所有选项卡都包含在滚动查看器中,并且DragDrop是TabControl的ItemsControl的附加属性。@Rachel,除了TabPanel之外,不能创建一个面板来反向重新排序它的子对象,并给他们想要的Z顺序吗?升级到.Net 4.0也解决了这个问题
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)));
}
}
}
}