【问题标题】:BringToFront in WPFWPF中的BringToFront
【发布时间】:2011-04-14 16:55:30
【问题描述】:

我需要在 WPF 中将自定义控件放在前面。

伪代码

OnMouseDown()
{
    if (this.parent != null)
        this.parent.BringToFront(this);
}

我知道,我知道有一个ZIndex,但是还是不明白怎么把简单的WinFormBringToFront替换成parent.SetZIndex(this, ?MaxZIndex(parent)? + 1)? p>

也许在像 WPF 这样很酷的东西中有更好的方法来做到这一点?!..

【问题讨论】:

  • @CodeNaked:也许这很重要,但是......我不知道,比如说,一个 UserControl...... Canvas、DockPanel、UIElement......
  • 你可以做 ((ContainerVisual)Control.Parent).Children 来获得视觉兄弟,但我知道这是你想要避免的。

标签: .net wpf wpf-controls


【解决方案1】:

这是一个扩展函数,它将 BringToFront 方法的功能添加到 Panel 中包含的所有 FrameworkElements。

  public static class FrameworkElementExt
  {
    public static void BringToFront(this FrameworkElement element)
    {
      if (element == null) return;

      Panel parent = element.Parent as Panel;
      if (parent == null) return;

      var maxZ = parent.Children.OfType<UIElement>()
        .Where(x => x != element)
        .Select(x => Panel.GetZIndex(x))
        .Max();
      Panel.SetZIndex(element, maxZ + 1);
    }
  }

【讨论】:

  • Panel.SetZIndex 是我需要的。谢谢。
【解决方案2】:

您所希望的最好的结果是使一个元素相对于同一父面板中的任何同级元素(例如 StackPanel、Grid、Canvas 等)处于最顶层。面板中项目的 z 顺序由 Panel.ZIndex 附加属性控制。

例如:

<Grid>
    <Rectangle Fill="Blue" Width="50" Height="50" Panel.ZIndex="1" />
    <Rectangle Fill="Red" Width="50" Height="50" Panel.ZIndex="0" />
</Grid>

在本例中,蓝色矩形将出现在顶部。这在blog post 中有更多解释。

还有一个问题是 Panel.ZIndex 的更改没有立即反映在 UI 中。有一个私有方法允许刷新 z-index,但由于它是私有的,因此使用它不是一个好主意。要解决此问题,您必须删除并重新添加子项。

但是,您不能将任何给定元素置于最顶层。例如:

<Grid>
    <Grid>
        <Rectangle Fill="Blue" Width="50" Height="50" Panel.ZIndex="1" />
        <Rectangle Fill="Red" Width="50" Height="50" Panel.ZIndex="0" />
    </Grid>
    <Grid>
        <Rectangle Fill="Green" Width="50" Height="50" Panel.ZIndex="0" />
        <Rectangle Fill="Yellow" Width="50" Height="50" Panel.ZIndex="0" />
    </Grid>
</Grid>

在这种情况下,将显示黄色矩形。因为第二个内部网格显示在第一个内部网格及其所有内容的顶部。您必须像这样更改它才能将蓝色矩形带到顶部:

<Grid>
    <Grid Panel.ZIndex="1">
        <Rectangle Fill="Blue" Width="50" Height="50" Panel.ZIndex="1" />
        <Rectangle Fill="Red" Width="50" Height="50" Panel.ZIndex="0" />
    </Grid>
    <Grid Panel.ZIndex="0">
        <Rectangle Fill="Green" Width="50" Height="50" Panel.ZIndex="0" />
        <Rectangle Fill="Yellow" Width="50" Height="50" Panel.ZIndex="0" />
    </Grid>
</Grid>

在处理 ItemsControl 时,this question 是相关的。大多数其他控件都有一个子控件,但您仍然需要将它们提前以使其中的任何一个子控件处于最顶层。

最后,Adorners 是将事物置于一切之上的好方法,但它们不是主视觉树的一部分。所以我不确定这是否适用于你的情况。

【讨论】:

  • 您有 Canvas.ZIndex、Panel.ZIndex 等......但是,正如我所见,唯一的解决方案是使用像 Canvas.SetZIndex(this, 99) 这样的代码,希望 99 是上面的元素。动态创建和添加新 UIElement 时并非总是如此...
  • @serhio - 实际上,Canvas.ZIndex 和 Panel.ZIndex 是一回事,Canvas 只是从 Panel 继承了它。但在 Silverlight 中,只有 Canvas 具有 ZIndex 属性。使用 SetZIndex 只是设置 Panel.ZIndex 附加属性的一种编程方式。使用像 99 这样的任意数字可能适用于您的情况,但通常需要做更多工作(即将所有同级 ZIndex 设置为 0)。
【解决方案3】:

我尝试了 canvas.zindex,但它没有用,但对我来说,解决方案是在 Popup 控件中使用 Border:

<Popup IsOpen="True/False">
    <Border Background="White">
        <DatePicker/>
    </Border>
</Popup>

【讨论】:

    【解决方案4】:

    我找到了更好的解决方案。得到它:

    foreach (var item in Grid1.Children)
    {
        if ((item as UIElement).Uid == "StackPan1")
        {
            UIElement tmp = item as UIElement;
            Grid1.Children.Remove(item as UIElement);
            Grid1.Children.Add(tmp);
            break;
        }
    }
    

    这只是示例,不是通用方法。但是您可以在动态添加控件的应用程序中使用它。这段代码只是添加了一个你想放在 UIElementCollection 顶部的元素。如果所有元素都具有相同的 ZIndex,它就可以工作。

    【讨论】:

      【解决方案5】:

      我只测试了一个 Window 控件,但是...

      this.Topmost = true;
      this.Topmost = false;
      

      第一行把它带到前面,第二行阻止它永久地放在前面。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-02
        • 1970-01-01
        • 1970-01-01
        • 2013-05-19
        • 2012-07-23
        • 1970-01-01
        相关资源
        最近更新 更多