C# FrameworkElement.BringToFront()和SendToBack()实现
我一直在寻找我希望的微不足道的东西,但显然不是,因为我可以在网上找到任何令人满意的东西:一个C# FrameworkElement.BringToFront()和SendToBack()实现,c#,wpf,C#,Wpf,我一直在寻找我希望的微不足道的东西,但显然不是,因为我可以在网上找到任何令人满意的东西:一个FrameworkElement.BringToFront()和FrameworkElement.SendToBack()的实现 我的场景是,我有几个自定义控件,它们由ContentPresenter在Canvas中呈现。我可以调试两个控件的可视树,如下所示: Element1: CustomControl {HashCode
FrameworkElement.BringToFront()
和FrameworkElement.SendToBack()
的实现
我的场景是,我有几个自定义控件,它们由ContentPresenter
在Canvas
中呈现。我可以调试两个控件的可视树,如下所示:
Element1:
CustomControl {HashCode: 35948007}
ContentPresenter {HashCode: 52397778}
Canvas {HashCode: 47345023}
ItemsPresenter {HashCode: 23452031}
Border {HashCode: 5260558}
ItemsControl {HashCode: 34643909}
...
Element2:
CustomControl {HashCode: 9741694}
ContentPresenter {HashCode: 3532547}
Canvas {HashCode: 47345023}
ItemsPresenter {HashCode: 23452031}
Border {HashCode: 5260558}
ItemsControl {HashCode: 34643909}
...
如您所见,它们的共同祖先是“Canvas{HashCode:47345023}”。设置自定义控件的Z索引也没有帮助,因为Z索引总是相对于它们没有的同级。我以下面的内容结束,它沿着可视化树查找第一个面板
,以及作为该面板子控件的自定义控件的祖先,以便设置该祖先的Z索引
public static void BringToFront(this FrameworkElement element)
{
setZIndex(element, indices => indices.Max() + 1);
}
public static void SendToBack(this FrameworkElement element)
{
setZIndex(element, indices => indices.Min() - 1);
}
private static void setZIndex(this FrameworkElement element, Func<IEnumerable<int>, int> indexCallback)
{
DependencyObject ancestor = element;
DependencyObject parent = VisualTreeHelper.GetParent(element);
while (parent != null && !(parent is Panel))
{
ancestor = parent;
parent = VisualTreeHelper.GetParent(parent);
}
if (parent is Panel panel && ancestor is UIElement ancestorElement)
{
var index = indexCallback(panel.ChildrenOfType<UIElement>().Select(e => Panel.GetZIndex(e)));
Panel.SetZIndex(ancestorElement, index);
}
}
publicstaticvoidbringtofront(此FrameworkElement)
{
setZIndex(元素,索引=>index.Max()+1);
}
公共静态void SendToBack(此FrameworkElement)
{
setZIndex(元素,索引=>index.Min()-1);
}
私有静态void setZIndex(此FrameworkElement元素,Func indexCallback)
{
DependencyObject祖先=元素;
DependencyObject parent=VisualTreeHelper.GetParent(元素);
while(parent!=null&&!(parent是面板))
{
祖先=父母;
父级=VisualTreeHelper.GetParent(父级);
}
if(父级为面板面板&&父级为UIElement AnteStorElement)
{
var index=indexCallback(panel.ChildrenOfType().Select(e=>panel.GetZIndex(e));
面板设置索引(ANCESTORELENT,索引);
}
}
问:这是一个好方法吗?它看起来很复杂…这不应该是“简单”的静态方法。两者都依赖于
画布的一个实例。扩展Canvas
或创建一个以Panel
为目标的附加行为,或者修改您的方法,将宿主Panel
作为参数,或者将这些方法转换为Panel
的扩展方法,这将更加优雅。通过这种方式,您始终可以直接访问宿主面板
,从而访问目标元素的所有同级。您只需设置Panel.ZIndex
,而无需在可视化树中搜索父Panel
。这将减少代码行数。@BionicCode但这正是我问题的一部分:控件是作为数据模板的一部分呈现的子控件-它们不知道(也不应该明确地知道)它们最终呈现在哪个面板中。我还认为这些项不必知道它们的面板,我没有想到这一点。我假设有一个对象知道哪个子对象属于哪个面板。负责更改这些子项的z索引的同一对象。如果您无法访问主机面板
,则搜索它是唯一的解决方案。你没有提供任何关于你如何使用你的方法的信息。我没有足够的信息来真正帮助或改进。我只是提供了一个不需要可视化树遍历的替代解决方案。