WPF Popup ZOrder

Max picture Max · Aug 12, 2009 · Viewed 12k times · Source

I am using a WPF Popup, but it popups up above every single window on my desktop, even when my application is minimized. How can I make it stay only on the window it originated? The same thing happens when my window is behind other windows: the popup displays above them all.

"There must be something can be done!"

Thanks.

Answer

Min picture Min · Sep 20, 2011

So I dug through the framework source code to see where it actually causes the window to be topmost and it does this in a private nested class. However, it does not provide an option to either just be a child popup of the main window or to be the topmost window. Here is a hack to make it always a child popup window. One could easily add a dependency property and do some more magic to make it the top most.

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);
            }
        }
    }
}