Click here to Skip to main content
15,883,749 members
Articles / Desktop Programming / WPF
Tip/Trick

Show() or Activate() a WPF window at the current mouse position

Rate me:
Please Sign up or sign in to vote.
4.86/5 (5 votes)
21 May 2012CPOL2 min read 45.8K   2   3
Using the Win32 API to place a WPF window on the currently active screen.

I'm currently developing a small productivity tool which has no start-up window defined. Whenever I press a hot-key, a window shows up and offers me some, hopefully useful, options. When I started writing the app I set the WindowStartupLocation property to CenterScreen. That was OK for me until I decided it's crap moving the mouse cursor from one corner of the screen to another. So I wanted this window showing up centered under the cursor, regardless on which screen I'm working. In addition, it shouldn't overlap the current screen boundary.

Quite easy task:

  • get the active screen
  • get the screen resolution
  • get the mouse position
  • place the window (centered) below.

Well, at least these were my thoughts.

I didn't take too much time figuring out that there is not such a nice Screen property like in Windows.Forms. At least you can get some information about your (primary) screen resolution in System.Windows.SystemParameters. Unfortunately if you are using more than one monitor and they don't have the same resolution, you are on your own. And oh, how to get the mouse position when you don't have anything you could pass to Mouse.GetPosition( IInputElement )? Wink | <img src= 

I had a little chat with my friend Google. A lot of guys told him to add a reference to Windows Forms - check my last question[^] here on CodeProject why I couldn't do this.

However, to make a long story short. I decided to come up with an extension method for the Windows.Window class. I'm invoking the native API to gather all information I need. I think it might be useful for some of you out there. At least I saw a lot of questions to this topic.

Check out the code. I dropped most of the comments for readability Big Grin | <img src= Kindly suggest improvements or alternatives. I'd like to see if there is a much better way. And oh, English isn't my first language. Kindly tell me what I did wrong so that I can correct it Smile | <img src=

The extension methods:

C#
namespace ExtensionMethods
{
    using System;
    using System.Runtime.InteropServices;
    using System.Windows;
 
    public static class WindowExtensions
    {
        #region Public Methods
 
        public static bool ActivateCenteredToMouse( this Window window )
        {
            ComputeTopLeft( ref window );
            return window.Activate();
        }
 
        public static void ShowCenteredToMouse( this Window window )
        {
            // in case the default start-up location isn't set to Manual
            WindowStartupLocation oldLocation = window.WindowStartupLocation;
            // set location to manual -> window will be placed by Top and Left property
            window.WindowStartupLocation = WindowStartupLocation.Manual;
            ComputeTopLeft( ref window );
            window.Show();
            window.WindowStartupLocation = oldLocation;
        }
 
        #endregion
 
        #region Methods
 
        private static void ComputeTopLeft( ref Window window )
        {
            W32Point pt = new W32Point();
            if ( !GetCursorPos( ref pt ) )
            {
                Marshal.ThrowExceptionForHR( Marshal.GetHRForLastWin32Error() );
            }
 
            // 0x00000002: return nearest monitor if pt is not contained in any monitor.
            IntPtr monHandle = MonitorFromPoint( pt, 0x00000002 );
            W32MonitorInfo monInfo = new W32MonitorInfo();
            monInfo.Size = Marshal.SizeOf( typeof( W32MonitorInfo ) );
 
            if ( !GetMonitorInfo( monHandle, ref monInfo ) )
            {
                Marshal.ThrowExceptionForHR( Marshal.GetHRForLastWin32Error() );
            }
 
            // use WorkArea struct to include the taskbar position.
            W32Rect monitor = monInfo.WorkArea;
            double offsetX = Math.Round( window.Width / 2 );
            double offsetY = Math.Round( window.Height / 2 );
 
            double top = pt.Y - offsetY;
            double left = pt.X - offsetX;
 
            Rect screen = new Rect (
                new Point( monitor.Left, monitor.Top ),
                new Point( monitor.Right, monitor.Bottom ) );
            Rect wnd = new Rect(
                new Point( left, top ),
                new Point( left + window.Width, top + window.Height ) );
 
            window.Top = wnd.Top;
            window.Left = wnd.Left;
 
            if ( !screen.Contains( wnd ) )
            {
                if ( wnd.Top < screen.Top )
                {
                    double diff = Math.Abs( screen.Top - wnd.Top );
                    window.Top = wnd.Top + diff;
                }
 
                if ( wnd.Bottom > screen.Bottom )
                {
                    double diff = wnd.Bottom - screen.Bottom;
                    window.Top = wnd.Top - diff;
                }
 
                if ( wnd.Left < screen.Left )
                {
                    double diff = Math.Abs( screen.Left - wnd.Left );
                    window.Left = wnd.Left + diff;
                }
 
                if ( wnd.Right > screen.Right )
                {
                    double diff = wnd.Right - screen.Right;
                    window.Left = wnd.Left - diff;
                }
            }
        }
 
        #endregion
 
        #region W32 API
 
        [DllImport( "user32.dll", SetLastError = true )]
        [return: MarshalAs( UnmanagedType.Bool )]
        private static extern bool GetCursorPos( ref W32Point pt );
 
        [DllImport( "user32.dll", SetLastError = true )]
        [return: MarshalAs( UnmanagedType.Bool )]
        private static extern bool GetMonitorInfo( IntPtr hMonitor, ref W32MonitorInfo lpmi );
 
        [DllImport( "user32.dll" )]
        private static extern IntPtr MonitorFromPoint( W32Point pt, uint dwFlags );
 
        [StructLayout( LayoutKind.Sequential )]
        public struct W32Point
        {
            public int X;
            public int Y;
        }
 
        [StructLayout( LayoutKind.Sequential )]
        internal struct W32MonitorInfo
        {
            public int Size;
            public W32Rect Monitor;
            public W32Rect WorkArea;
            public uint Flags;
        }
 
        [StructLayout( LayoutKind.Sequential )]
        internal struct W32Rect
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }
 
        #endregion
    }
}

How to use it:

Create an instance of any WPF window, e.g. FancyWindow or just MainWindow. Afterwards you can call the two extension methods.

C#
// FancyWindow is derived from System.Windows.Window
FancyWindow window = new FancyWindow();
...
window.ShowCenteredToMouse();
// or
window.ActivateCenteredToMouse();

I hope this is useful for at least one of you. And thanks for reading Smile | <img src=

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionThanks Pin
kmf25-Jan-14 4:59
kmf25-Jan-14 4:59 
QuestionHow to Use??? Pin
mshahbazm21-May-12 6:28
mshahbazm21-May-12 6:28 
AnswerRe: How to Use??? Pin
SvenMe21-May-12 6:39
SvenMe21-May-12 6:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.