question

KarmelCohen-3060 avatar image
0 Votes"
KarmelCohen-3060 asked ·

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

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-wpf
· 1
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I can't find the method to ignore WindowStartupLocation in the official documentation. Can you try some other workarounds? For example, set the window. Left and window. Top properties of the window locate the position of the new windows.

0 Votes 0 · ·

1 Answer

gekka avatar image
0 Votes"
gekka answered ·

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
     }
 }
· Share
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.