The WPF Popup control is always “topmost” over other application windows.  If you’re happy with a dirty workaround to remove the Topmost state, you can derive your own Popup control similar to this:

public class PopupNonTopmost : Popup
{
    protected override void OnOpened( EventArgs e )
    {
        var hwnd = ( (HwndSource)PresentationSource.FromVisual( this.Child ) ).Handle;
        RECT rect;

        if ( GetWindowRect( hwnd, out rect ) )
        {
            SetWindowPos( hwnd, -2, rect.Left, rect.Top, (int)this.Width, (int)this.Height, 0 );
        }
    }

    #region P/Invoke imports & definitions

    [StructLayout( LayoutKind.Sequential )]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    [DllImport( "user32.dll" )]
    [return: MarshalAs( UnmanagedType.Bool )]
    private static extern bool GetWindowRect( IntPtr hWnd, out RECT lpRect );

    [DllImport( "user32", EntryPoint = "SetWindowPos" )]
    private static extern int SetWindowPos( IntPtr hWnd, int hwndInsertAfter, int x, int y, int cx, int cy, int wFlags );

    #endregion
}

This is based on code by digitalnetbizz, with the addition of calling GetWindowRect for the current window position.  Obviously it’d be nicer if Popup had a Topmost DependencyProperty you could use.  Here’s my attempt which borrows the Window element’s TopmostProperty:

public class PopupNonTopmost : Popup
{
    public static DependencyProperty TopmostProperty = Window.TopmostProperty.AddOwner(
        typeof( PopupNonTopmost ),
        new FrameworkPropertyMetadata( false, OnTopmostChanged ) );

    public bool Topmost
    {
        get { return (bool)GetValue( TopmostProperty ); }
        set { SetValue( TopmostProperty, value ); }
    }

    private static void OnTopmostChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e )
    {
        ( obj as PopupNonTopmost ).UpdateWindow();
    }

    protected override void OnOpened( EventArgs e )
    {
        UpdateWindow();
    }

    private void UpdateWindow()
    {
        var hwnd = ( (HwndSource)PresentationSource.FromVisual( this.Child ) ).Handle;
        RECT rect;

        if ( GetWindowRect( hwnd, out rect ) )
        {
            SetWindowPos( hwnd, Topmost ? -1 : -2, rect.Left, rect.Top, (int)this.Width, (int)this.Height, 0 );
        }
    }

    #region P/Invoke imports & definitions

    [StructLayout( LayoutKind.Sequential )]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    [DllImport( "user32.dll" )]
    [return: MarshalAs( UnmanagedType.Bool )]
    private static extern bool GetWindowRect( IntPtr hWnd, out RECT lpRect );

    [DllImport( "user32", EntryPoint = "SetWindowPos" )]
    private static extern int SetWindowPos( IntPtr hWnd, int hwndInsertAfter, int x, int y, int cx, int cy, int wFlags );

    #endregion
}

I’ve not tested this extensively (it compiled :) ), so just let me know if it’s not happy!  Likewise if I’ve missed a glaringly obvious shiny new Topmost property in WPF, let me know :)

About these ads