WPF - Is there a way to get Windows to ignore the manual WindowStartupLocation I'm using for a particular window?

Karmel Cohen 1 Reputation point
2020-05-12T08:53:20.903+00:00

I'm using WindowStartupLocation.Manual to open a window on my app and I wonder if there is a way to tell Windows to ignore that location and do not open the next window after this one (where it is not mentioned a specific location for it) following my window's location..

"Setting the WindowStartupLocation property to Manual causes a window to be positioned according to its Left and Top property values. If either the Left or Top properties aren't specified, their values are determined by Windows."

The thing is, I'm adding a new window to a legacy application.. I open it on a very specific location.. but after that, some of the other windows of that same application are opened at a location based on the location I gave to the new window.. I guess that it is due to the fact that some of the other windows does not have a specify location assigned to them..

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,669 questions
{count} votes

1 answer

Sort by: Most helpful
  1. gekka 6,436 Reputation points MVP
    2020-05-14T00:18:40.347+00:00

    HI,

    You can't ignore WindowStartupLocation because WPF system will specify it as a window creation parameter, but you can move it around at the time the window is created.

    namespace WpfApp1
    {
        using System;
        using System.Collections.Generic;
        using System.Data;
        using System.Linq;
        using System.Windows;
        using System.Windows.Interop;
        using Gekka.Tools.Windows;
    
        public partial class App : Application
        {
            private ShellHook hook;
            private Dictionary<Type, Rect> dicRects = new Dictionary<Type, Rect>();
    
            protected override void OnStartup(StartupEventArgs e)
            {
                hook = new ShellHook();
                hook.WindowCreated += Hook_WindowCreated;
    
                base.OnStartup(e);
            }
    
            private void Hook_WindowCreated(object sender, ShellHook.HookEventArgs e)
            {
                var w = HwndSource.FromHwnd(e.wParam).RootVisual as Window;
                if (w != null && w.WindowStartupLocation == WindowStartupLocation.Manual)
                {
                    if (!double.IsNaN(w.Left) && !double.IsNaN(w.Top))
                    {
                        List<Window> windows = this.Windows
                                 .OfType<Window>()
                                 .Where(_ => _ != w)
                                 .Where(_ => _.IsVisible)
                                 .ToList();
                        while (windows.Any(_ => _.Top == w.Top && _.Left == w.Left))
                        {
                            //If the window is overlapped, it is try move.
                            //But, you may see a ghost of the window slightly.
                            w.Left += SystemParameters.WindowCaptionHeight;
                            w.Top += SystemParameters.WindowCaptionHeight;
                        }
                    }
    
                    w.Closing += (a, b) =>
                    {
                        dicRects[w.GetType()] = new Rect(w.Left, w.Top, w.Width, w.Height);
                    };
                }
            }
    
            protected override void OnExit(ExitEventArgs e)
            {
                hook?.Dispose();
                base.OnExit(e);
            }
        }
    }
    
    namespace Gekka.Tools.Windows
    {
        using System;
        using System.Runtime.InteropServices;
    
        public static class Win32API
        {
            #region "API"
    
            [DllImport("user32.dll")]
            internal extern static int UnhookWindowsHookEx(int hHook);
    
            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            internal extern static int GetCurrentThreadId();
    
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            internal extern static int SetWindowsHookEx(int idHook, HookCallDelegate lpfn, IntPtr hmod, int dwThreadId);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
            public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
    
            internal delegate int HookCallDelegate(int nCode, IntPtr wParam, IntPtr lParam);
    
            [DllImport("kernel32.dll")]
            public static extern IntPtr GetModuleHandle(string name);
            #endregion
    
            internal enum WH
            {
                WH_CBT = 5,
                WH_SHELL = 10
            }
            internal enum GWL
            {
                GWL_HINSTANCE = -6
            }
            internal enum HSHELL
            {
                HSHELL_WINDOWCREATED = 1,
                HSHELL_WINDOWDESTROYED = 2,
                HSHELL_ACTIVATESHELLWINDOW = 3
            }
    
            public static IntPtr GetHINSTANCE()
            {
                var mod = GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName);
                var hinst = Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]);
                return hinst;
            }
        }
    
        public class ShellHook : IDisposable
        {
            public class HookEventArgs
            {
                public HookEventArgs(int nCode, IntPtr wParam, IntPtr lParam)
                {
                    this.nCode = nCode;
                    this.wParam = wParam;
                    this.lParam = lParam;
                }
                public int nCode { get; }
                public IntPtr wParam { get; }
                public IntPtr lParam { get; }
            }
    
            public event EventHandler<HookEventArgs> WindowCreated;
    
            private int _hHook = 0;
            private Win32API.HookCallDelegate callback;
    
            public ShellHook()
            {
                var threadid = Win32API.GetCurrentThreadId();
                var hinst = Win32API.GetHINSTANCE();
                this.callback = new Win32API.HookCallDelegate(ShellHookCall);
    
                _hHook = Win32API.SetWindowsHookEx((int)Win32API.WH.WH_SHELL, callback, hinst, threadid);
            }
    
            private int ShellHookCall(int nCode, IntPtr wParam, IntPtr lParam)
            {
                if (nCode < 0)
                {
                    return Win32API.CallNextHookEx(_hHook, nCode, wParam, lParam);
                }
                else
                {
                    switch ((Win32API.HSHELL)nCode)
                    {
                    case Win32API.HSHELL.HSHELL_WINDOWCREATED:
                        WindowCreated?.Invoke(this, new HookEventArgs(nCode, wParam, lParam));
                        break;
                    case Win32API.HSHELL.HSHELL_ACTIVATESHELLWINDOW:
                    case Win32API.HSHELL.HSHELL_WINDOWDESTROYED:
                        break;
                    default:
                        break;
                    }
                    return 0;
                }
            }
    
            public void UnHook()
            {
                if (_hHook != 0)
                {
                    Win32API.UnhookWindowsHookEx(_hHook);
                    _hHook = 0;
                }
            }
    
            #region IDisposable メンバ
    
            private bool disposed = false;
            protected virtual void Dispose(bool isnotFromFinalizer)
            {
                if (!this.disposed) { UnHook(); }
                this.disposed = true;
            }
    
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
    
            ~ShellHook() { this.Dispose(false); }
    
            #endregion
        }
    }
    
    0 comments No comments