WPF弹出窗口层叠顺序

5

我正在使用一个WPF弹出窗口,但它会在我的桌面上方弹出,即使我的应用程序被最小化。我该如何让它只停留在它所属的窗口上?当我的窗口在其他窗口后面时,同样的事情也会发生:弹出窗口显示在所有窗口的上方。

"一定有办法可以解决的!"

谢谢。


1
我遇到了同样的问题,但无法解决。很难相信这是默认行为,但MSDN对此毫无用处。我解决的方法是在窗口xaml中将包含comboBox的整个窗口设置为TopMost=True。这使整个窗口都置顶,而不仅仅是我的ComboBox下拉列表(与您的弹出窗口情况相同)。 - pixel
5个回答

9

所以,我查看了框架源代码,看看它在哪里导致窗口始终处于最顶层,它是在一个私有嵌套类中实现的。然而,它没有提供选项来仅作为主窗口的子弹出窗口或者成为最顶层窗口。这里有一个技巧可以使它始终成为子弹出窗口。可以轻松地添加依赖属性并进行更多的操作,使其成为最顶层窗口。

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Controls.Primitives;

namespace UI.Extensions.Wpf.Controls
{
    public class ChildPopup : Popup
    {
        static ChildPopup()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ChildPopup), new FrameworkPropertyMetadata(typeof(ChildPopup)));
        }

        public ChildPopup()
        {
            Type baseType = this.GetType().BaseType;
            dynamic popupSecHelper = GetHiddenField(this, baseType, "_secHelper");
            SetHiddenField(popupSecHelper, "_isChildPopupInitialized", true);
            SetHiddenField(popupSecHelper, "_isChildPopup", true);
        }

        protected dynamic GetHiddenField(object container, string fieldName)
        {
            return GetHiddenField(container, container.GetType(), fieldName);
        }

        protected dynamic GetHiddenField(object container, Type containerType, string fieldName)
        {
            dynamic retVal = null;
            FieldInfo fieldInfo = containerType.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
            if (fieldInfo != null)
            {
                retVal = fieldInfo.GetValue(container);
            }
            return retVal;
        }

        protected void SetHiddenField(object container, string fieldName, object value)
        {
            SetHiddenField(container, container.GetType(), fieldName, value);
        }

        protected void SetHiddenField(object container, Type containerType, string fieldName, object value)
        {
            FieldInfo fieldInfo = containerType.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
            if (fieldInfo != null)
            {
                fieldInfo.SetValue(container, value);
            }
        }
    }
}

2
如果您像我一样需要从ChildPopup继承代码,那么原始代码将无法正常工作。我将popupSecHelper行更改为以下内容: object popupSecHelper = GetHiddenField(this, typeof(Popup), "_secHelper");此外,我跳过了DefaultStyleKeyProperty重写,因为似乎不需要,并且我看不出为什么需要它。 - TGasdf

4
我试过解决这个问题,但是没有找到好的解决方案。这似乎是它应该工作的方式,你不能覆盖它。
我想到的唯一解决方案是使用普通布局面板并提高它的Z-Index,使其成为最上层控件(这种情况类似于弹出)。我发现这种方法不起作用的唯一情况是当你通过WindowsFormsHosts在屏幕上放置WinForms时。那些Winforms总是比任何WPF东西都要高的Z-Index。这就是需要使用Popup来避免它的情况。

3
这是我的解决方法:
    private void Popup_Opened(object sender, EventArgs events)
    {
        Popup popup = (Popup)sender;

        // Get window to make popop follow it when user change window's location.
        Window w = Window.GetWindow(popup);
        // Popups are always on top, so when another window gets focus, we
        // need to close all popups.
        w.Deactivated += delegate (object s, EventArgs e)
        {
            popup.IsOpen = false;
        };
        // When our dialog gets focus again, we show it back.
        w.Activated += delegate (object s, EventArgs e)
        {
            popup.IsOpen = true;
        };
     }

1
在弹出警报时,主窗口不会停用,并且弹出的消息会出现在后面。 - Fabrice T


0

虽然我没有尝试过,但我也读到可以使用装饰器来实现这一点...当被问及同样的问题时,Matt Galbraith在MSDN论坛上建议了这种方法...以防仍有人在阅读此帖。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接