Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Popup ZOrder

Tags:

c#

wpf

xaml

z-order

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.

like image 407
Max Avatar asked Aug 12 '09 16:08

Max


4 Answers

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);
            }
        }
    }
}
like image 74
Min Avatar answered Nov 13 '22 11:11

Min


I've tried to solve this issue as well, and have found no good solution. This seems to be the way it is supposed to work, and you can't override that.

The only solution I've come up with is to just use a regular layout panel and raise it's Z-Index, so it is the top-level control (this sort of simulates the Popup). The only time I have found that this won't work is when you have WinForms on the screen through WindowsFormsHosts. Those Winforms are always at a higher Z-Index than any of the WPF stuff. That is when you have to use a Popup to get around it.

like image 22
timothymcgrath Avatar answered Nov 13 '22 11:11

timothymcgrath


Check this: http://chriscavanagh.wordpress.com/2008/08/13/non-topmost-wpf-popup/

may be this can help you!!

like image 2
viky Avatar answered Nov 13 '22 11:11

viky


That's how I solved it:

    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;
        };
     }
like image 2
Leonard Keret Avatar answered Nov 13 '22 12:11

Leonard Keret