Wouldn't the behavior you want be achieved by setting the Owner property instead of setting the Topmost property for sub-window?
public partial class MainWindow : Window
{
public MainWindow()
{
//InitializeComponent();
this.Title = "MainWindow";
this.Width = 400;
this.Height = 400;
this.Background = Brushes.LimeGreen;
this.ShowInTaskbar = true;
this.Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Window subWindow = new Window();
subWindow.Title = "SubWindow";
subWindow.Width =300;
subWindow.Height = 100;
subWindow.Background = Brushes.Yellow;
subWindow.ShowInTaskbar = false;
//subWindow.Topmost = true; // not set Topmost
subWindow.Owner = this; // set owner
subWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
subWindow.Show();
}
}
For external processes, etc., the Owner must be changed using SetWindowLongPtr (Windows API).
using System;
using System.Windows;
public partial class App : Application
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool IsWindow(IntPtr hwnd);
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, GWL nIndex, IntPtr dwNewLong);
enum GWL : int
{
GWL_HWNDPARENT = -8,
}
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern int SetParent(IntPtr hwndParent, IntPtr hwndChild);
protected override void OnStartup(StartupEventArgs e)
{
System.Diagnostics.Debugger.Launch();
System.Diagnostics.Debugger.Break();
IntPtr hwndOnwer = IntPtr.Zero; ;
if (e.Args.Length > 0)
{ // receive Owner Window Handle
if (long.TryParse(e.Args[0], System.Globalization.NumberStyles.HexNumber, null, out long number) && number > 0)
{
hwndOnwer = new IntPtr(number);
if (!IsWindow(hwndOnwer))
{
hwndOnwer = IntPtr.Zero;
}
}
}
var wnd = new Window(); //remove StartupUri from app.xaml
if (hwndOnwer == IntPtr.Zero)
{
wnd.Title = "MainWindow";
wnd.Width = 400;
wnd.Height = 300;
wnd.Background = System.Windows.Media.Brushes.LimeGreen;
wnd.Loaded += (sender2, e2) =>
{
IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(wnd).Handle;
var path = System.Environment.ProcessPath;
System.Diagnostics.Process.Start(path, hwnd.ToString("X"));
};
}
else
{
wnd.Title = "SubWindow";
wnd.Width = 300;
wnd.Height = 200;
wnd.Background = System.Windows.Media.Brushes.Yellow;
wnd.ShowInTaskbar = false;
wnd.Loaded += (sender2, e2) =>
{
//Set Owner Window insted of Window.Owner property
IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(wnd).Handle;
SetWindowLongPtr(hwnd, GWL.GWL_HWNDPARENT, hwndOnwer);
};
}
wnd.Show();
}
}
[2023-12-21T18:30Z+9:00] Add sample 2
Added a sample of setting the owner from an external process window.
Thank you so much for the answer.
Can you please help me how to implement the following:
When I create the external window i use the following code to clone a process for the external window. The process send 3 arguments (mmfName , semaphoreNameOut , and semaphoreNameIn ).
So the argument type that is sent by the process is string. How can I send the the main window as a parent to be read in this line of code as what you did:
if (long.TryParse(e.Args[0], System.Globalization.NumberStyles.HexNumber, null, out long number) && number > 0)
when arguments are received by the external window I read them as an array of strings as follows:
public ExternBuilder(string[] args)
{
if(args.length>=3)
{
//load main parameters through app arguments
string MMFName = args[0];
string SemaphoreNameIn = args[1];
string SemaphoreNameOut = args[2];
}
}