74

I have a WPF application and I need to know how to center the wain window programatically (not in XAML).

I need to be able to do this both at startup and in response to certain user events. It has to be dynamically calculated since the window size itself is dynamic.

What's the simplest way to do this? Under old Win32 code, I'd call the system metrics functions and work it all out. Is that still the way it's done or is there a simple CenterWindowOnScreen() function I can now call.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953

16 Answers16

105

Well, for startup time, you can set the startup location:

window.WindowStartupLocation = WindowStartupLocation.CenterScreen;

Later, you'll need to query it. The information (at least for the primary screen) is available via SystemParameters.PrimaryScreenWidth/Height.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
98
private void CenterWindowOnScreen()
{
    double screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
    double screenHeight = System.Windows.SystemParameters.PrimaryScreenHeight;
    double windowWidth = this.Width;
    double windowHeight = this.Height;
    this.Left = (screenWidth / 2) - (windowWidth / 2);
    this.Top = (screenHeight / 2) - (windowHeight / 2);
}

You can use this method to set the window position to the center of your screen.

Ivan Yurchenko
  • 3,762
  • 1
  • 21
  • 35
Gramero
  • 1,835
  • 3
  • 24
  • 26
  • 1
    I'll give you one for that but I seem to recall it's a lot more work, taking into account task bars and so forth. Still, +1 for the `SystemParameters` and some code so I don't have to go out to `GetSystemMetrics` myself. – paxdiablo Oct 26 '10 at 09:48
  • Possibly the only way to re-center the window after programmatically changing the window Height and/or Width or after its location has been changed. – azarc3 Mar 15 '15 at 16:24
  • 10
    This only works if you have 1 monitor, or if all your monitors are the same size – JumpingJezza Sep 16 '15 at 04:25
  • 1
    A little distributive property of division because division is more expensive in the way of performance than substraction:" this.Left = (screenWidth - windowWidth)/2;" etc... – BoiseBaked Oct 24 '18 at 18:00
  • does not work for me with multiple monitors. it ends up being quite off center – Welcor Jul 12 '21 at 12:27
88

Isn't it just as simple to set

WindowStartupLocation="CenterScreen"

In the XAML definition for the window.

Navnath Godse
  • 2,233
  • 2
  • 23
  • 32
naskew
  • 2,091
  • 1
  • 19
  • 20
  • 4
    That's fine for the startup location but, as I pointed out in the question, I also want to do this from within the program when the window changes size. – paxdiablo Aug 28 '13 at 08:18
  • Sorry, yes you are right. I wondered why so many people seemed to go for the non obvious solution. :-) – naskew Aug 29 '13 at 08:36
26

I had to combine a few of these answers to cover all bases in my case:

  • Peter's method to find the current monitor - rather than the just the Primary monitor (seriously who has just 1 monitor at work anymore?)
  • @Wild_A's method to use the workarea rather than the screen bounds to take into account the space for the taskbar.
  • I had to add DPI scaling, specifically for a tablet displaying 1280x800 as 1024x640, but which is useful to cover edge cases, for which I found an answer for here. Note the dpiScaling variable is null if called on first load before the UI is displayed (explained here)
//get the current monitor
Screen currentMonitor = Screen.FromHandle(new System.Windows.Interop.WindowInteropHelper(Application.Current.MainWindow).Handle);

//find out if our app is being scaled by the monitor
PresentationSource source = PresentationSource.FromVisual(Application.Current.MainWindow);
double dpiScaling = (source != null && source.CompositionTarget != null ? source.CompositionTarget.TransformFromDevice.M11 : 1);

//get the available area of the monitor
Rectangle workArea = currentMonitor.WorkingArea;
var workAreaWidth = (int)Math.Floor(workArea.Width*dpiScaling);
var workAreaHeight = (int)Math.Floor(workArea.Height*dpiScaling);

//move to the centre
Application.Current.MainWindow.Left = (((workAreaWidth - (myWindowWidth * dpiScaling)) / 2) + (workArea.Left * dpiScaling));
Application.Current.MainWindow.Top = (((workAreaHeight - (myWindowHeight * dpiScaling)) / 2) + (workArea.Top * dpiScaling));

where myWindowWidth and myWindowHeight are variables I used to manually set the size of the window earlier.

Community
  • 1
  • 1
JumpingJezza
  • 5,498
  • 11
  • 67
  • 106
  • I have just one monitor - 40" with 4K resolution. Can't see why anyone would need more than one (or who would have more desk space). ;) – CramerTV Jan 10 '17 at 23:27
  • 1
    @CramerTV Ha true! The times they are a changing :) Although still relevant for plugging into a monitor for demos – JumpingJezza Jan 11 '17 at 00:35
  • 2
    Great combination of two answers, just used this and it worked perfectly. And yes I used 3 screens- one with Visual Studio, one with a pdf(ebook), one with stackoverflow/outlook – JohnChris May 25 '17 at 14:14
  • 2
    This should definitively be the answer – JobaDiniz Sep 08 '17 at 13:00
22
Rect workArea = System.Windows.SystemParameters.WorkArea;
this.Left = (workArea.Width - this.Width) / 2 + workArea.Left;
this.Top = (workArea.Height - this.Height) / 2 + workArea.Top;

This takes into account the taskbar size (by using System.Windows.SystemParameters.WorkArea) and position (by adding workArea.Left and workArea.Top)

JumpingJezza
  • 5,498
  • 11
  • 67
  • 106
Wild_A
  • 346
  • 2
  • 7
8

In case you need to draw a window in an multiple screen environment. I've made a static class where the following method can be re-used:

public static void PostitionWindowOnScreen(Window window, double horizontalShift = 0, double verticalShift = 0)
{
    Screen screen = Screen.FromHandle(new System.Windows.Interop.WindowInteropHelper(window).Handle);
    window.Left = screen.Bounds.X + ((screen.Bounds.Width - window.ActualWidth) / 2) + horizontalShift;
    window.Top = screen.Bounds.Y + ((screen.Bounds.Height - window.ActualHeight) / 2) + verticalShift;        
}

In the constructor of the Window now just call the method:

this.Loaded += (s, a) => Globals.PostitionWindowOnScreen(this, 0, 0)
JumpingJezza
  • 5,498
  • 11
  • 67
  • 106
Peter
  • 81
  • 1
  • 2
  • For some reason, this method positions my window 20 pixels away from the top? This is working better for me than the chosen answer. – Andy Apr 24 '15 at 13:12
4

As a basic solution, you can use the window's StartupLocation property, set it to one of the enum values defined in System.Windows.WindowStartupLocation enumeration, there is one for center of screen:

_wpfWindow.StartupLocation = System.Windows.WindowStartupLocation.CenterScreen;

Unfortunately it's not always quite so simple; you need to account for multiple monitors, taskbars, etc. The "CenterScreen" option opens the window in the center of the screen that has the mouse cursor. See this SO question for a lot of information, or reference the api.

Community
  • 1
  • 1
Guy Starbuck
  • 21,603
  • 7
  • 53
  • 64
3

In the window element just add this attribute-value pair: WindowStartupLocation="CenterScreen"

Husam Hilal
  • 107
  • 1
  • 1
  • 4
    "Programatically, _not_ in XAML". In any case, isn't this just a duplicate of naskew's answer? – paxdiablo Mar 21 '14 at 22:14
  • Thank you for this answer! I am working in a shop where we do everything in xaml. The "programmatic" way is clever, but is not the WPF way. – James Sep 03 '14 at 14:22
  • So, @James, what is the WPF way to increase your windows size and still keep it centered? The specific use case I had was a 80x24 terminal window for which you could change the font size. In order to maintain visible 80x24 characters, the window size had to increase but I wanted to keep it centered. – paxdiablo Aug 14 '19 at 00:50
3

What I am using in my app, it is working for multiple displays and for different DPI setting

    //center a window on chosen screen
    public static void CenterWindow(Window w, System.Windows.Forms.Screen screen = null)
    {
        if(screen == null)
            screen = System.Windows.Forms.Screen.PrimaryScreen;

        int screenW = screen.Bounds.Width;
        int screenH = screen.Bounds.Height;
        int screenTop = screen.Bounds.Top;
        int screenLeft = screen.Bounds.Left;

        w.Left = PixelsToPoints((int)(screenLeft + (screenW - PointsToPixels(w.Width, "X")) / 2), "X");
        w.Top = PixelsToPoints((int)(screenTop + (screenH - PointsToPixels(w.Height, "Y")) / 2), "Y");
    }

    public static double PixelsToPoints(int pixels, string direction)
    {
        if (direction == "X")
        {
            return pixels * SystemParameters.WorkArea.Width / System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width;
        }
        else
        {
            return pixels * SystemParameters.WorkArea.Height / System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
        }
    }

    public static double PointsToPixels(double wpfPoints, string direction)
    {
        if (direction == "X")
        {
            return wpfPoints * System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width / SystemParameters.WorkArea.Width;
        }
        else
        {
            return wpfPoints * System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height / SystemParameters.WorkArea.Height;
        }
    }
vinsa
  • 1,132
  • 12
  • 25
2

Based on @Wild_A answer I just subscribed to the SizeChanged event, and added this event handler:

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
    try
    {
        Rect workArea = SystemParameters.WorkArea;
        this.Left = (workArea.Width - e.NewSize.Width) / 2 + workArea.Left;
        this.Top = (workArea.Height - e.NewSize.Height) / 2 + workArea.Top;
    }
    catch (Exception ex) { ... Handel exception; }
}
Viking
  • 293
  • 4
  • 12
2

Just use:

WindowStartupLocation="CenterScreen"

And in case you only want to center horizontally / vertically, You can override the OnActivated method and set left or top to zero like this:

    protected override void OnActivated(EventArgs e)
    {
        base.OnActivated(e);

        // to center Vertically
        Left = 0;
        // or user top = 0 to center Horizontally
        //top = 0;
    }
TornadoHell
  • 141
  • 6
2

Another short way to make mainwindow render at center of the computer screen using code behind.

this.Left = (System.Windows.SystemParameters.PrimaryScreenWidth - this.Width)/2;
this.Top = (System.Windows.SystemParameters.PrimaryScreenHeight - this.Height)/2;
Udin M
  • 51
  • 5
1

Copy-paste good quality extension code.

Runtime:

using System;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;

namespace Extensions
{
    /// <summary>
    /// <see cref="Window"/> extensions.
    /// </summary>
    public static class WindowExtensions
    {
        /// <summary>
        /// Moves the window to the center of the current screen, also considering dpi.
        /// </summary>
        /// <param name="window"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void MoveToCenter(this Window window)
        {
            window = window ?? throw new ArgumentNullException(nameof(window));

            var helper = new WindowInteropHelper(window);
            var screen = Screen.FromHandle(helper.Handle);
            var area = screen.WorkingArea;

            var source = PresentationSource.FromVisual(window);
            var dpi = source?.CompositionTarget?.TransformFromDevice.M11 ?? 1.0;

            window.Left = dpi * area.Left + (dpi * area.Width - window.Width) / 2;
            window.Top = dpi * area.Top + (dpi * area.Height - window.Height) / 2;
        }
    }
}

Initial position:

<Window WindowStartupLocation="CenterScreen">
</Window>
Konstantin S.
  • 1,307
  • 14
  • 19
0

Go to property window of MainWindow.xaml

  • find WindowStartupLocation property from Common category
  • select CenterScreen option from dropdown
  • Run the Application

For Full Screen

Go to property window of MainWindow.xaml

  • find WindowState property from Common category
  • select Maximized option from dropdown
  • Run the Application
-1

You will have to find this line : Title="MainWindow" Height="450" Width="800"

And you add this line to it : WindowStartupLocation="CenterScreen"

To become this : Title="MainWindow" Height="450" Width="800" WindowStartupLocation="CenterScreen">

Thank me Later ♥

TOUSSIA
  • 9
  • 1
-2

If you it to be maximized at once
this.WindowState = System.Windows.WindowState.Maximized;

EpiGen
  • 70
  • 6