Open Window on the Same Monitor as MainWindow - c#

I've seen many questions regarding similar issues, but I haven't found one quite specific enough to my question to find an answer yet.
I allow the user to move the MainWindow of my program around and, if they have one, onto another monitor. When they click to add something on the MainWindow, a new Window is created so they can fill in a form.
The problem is that this new Window will start on the primary screen of the OS instead of starting on the screen that the MainWindow is currently located on.
I had a look at this question; How to make a dialog(view) open up on the same monitor as the main window and saw that setting the owner to the MainWindow worked in this case. So I added
Owner = Application.Current.MainWindow;
into the Window_Loaded method the new Window. This does load the Window on the same screen as the MainWindow but then crashes, stating Cannot set Owner property after Dialog is shown.
Naturally I move the setting of the Owner property to before the new Window is shown, so it looks like this;
contractAddwindow.Owner = Application.Current.MainWindow;
contractAddwindow.ShowDialog();
however this then has the same issue as before, the contractAddWindow starts on the primary screen.
So my question is, how do I force the new Window to load on the same monitor as the MainWindow instead of the primary screen?

You can use WindowStartupLocation:
From XAML:
WindowStartupLocation="CenterOwner"
From Code:
WindowStartupLocation = WindowStartupLocation.CenterOwner;

#EDIT: Consider trying Nawed's answer (see below) before using this one. His is much simpler.
Try this methods:
using System.Windows;
using System.Windows.Forms; // Reference System.Drawing
[...]
public void SetWindowScreen(Window window, Screen screen)
{
if (screen != null)
{
if (!window.IsLoaded)
{
window.WindowStartupLocation = WindowStartupLocation.Manual;
}
var workingArea = screen.WorkingArea;
window.Left = workingArea.Left;
window.Top = workingArea.Top;
}
}
public Screen GetWindowScreen(Window window)
{
return Screen.FromHandle(new System.Windows.Interop.WindowInteropHelper(window).Handle);
}
And then, call it like this from the constructor of the Window you want to show on the same monitor as the MainWindow:
SetWindowScreen(this, GetWindowScreen(App.Current.MainWindow));

Related

WPF window should be modal to native owner window, but isn't

I have the following C# code in a WPF project:
private static void RunConfig(string owner)
{
long ownerHandle;
var settingsWindow = new SettingsWindow();
if (long.TryParse(owner, out ownerHandle))
{
WindowInteropHelper helper = new WindowInteropHelper(settingsWindow);
helper.Owner = new IntPtr(ownerHandle);
}
settingsWindow.ShowDialog();
}
The SettingsWindow isn't properly modal to the owner window (i.e. I can focus on, interact with, and even close the owner window while the SettingsWindow is still open). What am I doing wrong?
For context, this code is part of a screen saver program, and the owner window is the Control Panel screen saver selection window (which passes in the handle to use as owner via command line parameter). I know the IF statement is evaluating true and correctly parsing the handle.
I have also tried using the SetWindowLongPtr method from user32.dll (compiling for x64, hence not using SetWindowLong) which is briefly described here and shown in use here. This method works in WinForms, but doesn't seem to work here in WPF. Help me Obi-Wan Kenobi, you're my only hope.
It turns out that using WindowInteropHelper to set the native window as owner of the WPF Window does work, it just doesn't do the whole job. When set this way, the WPF Window will remain visible on top of the native window, even if the native window has focus. However, that is the only effect obtained. The WPF Window does not prevent interaction with the native Window, and the native window can even be closed, without the WPF Window closing or being affected.
In order to get the rest of the desired behaviour, we need to use the EnableWindow function in user32.dll to disable the native Window before calling ShowDialog on the WPF Window, and again to re-enable it once the WPF Window closes.
The modified code looks like this:
private static void RunConfig(string owner)
{
long ownerHandle;
var settingsForm = new SettingsWindow();
if (long.TryParse(owner, out ownerHandle))
{
WindowInteropHelper helper = new WindowInteropHelper(settingsForm);
helper.Owner = new IntPtr(ownerHandle);
NativeMethods.EnableWindow(helper.Owner, false);
settingsForm.ShowDialog();
NativeMethods.EnableWindow(helper.Owner, true);
}
else
{
settingsForm.ShowDialog();
}
}
(Note: The above code is correct in general, but incomplete in the case of screen savers, which is what this code is actually being used for. In the case that this code is being used for the config window of a screen saver, the string passed in for the owner handle is not the handle of the Control Panel window to be used as owner, but rather a handle for a control that is a child of the Control Panel window. The extra step in this case is to get the handle of the parent of that control. We can do this by calling GetParent, also in user32.dll, on the passed-in handle. This will return the real handle we want to use for the owner and EnableWindow calls.)
If anyone from Microsoft ever finds this, maybe consider modifying WindowInteropHelper to properly set all of this up when Owner is assigned and ShowDialog used, since this is the proper complete behavior for modal windows.

Why does closing the last child window minimize its parent window?

I have the following simple wpf application:
App.xaml:
<Application x:Class="TestWpf2.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Application>
App.xaml.cs:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
var parentWindow = new Window();
parentWindow.Show();
var childWindow1 = new Window { Owner = parentWindow };
childWindow1.Show();
var childWindow2 = new Window { Owner = parentWindow };
childWindow2.Show();
}
}
The application causes 3 windows to appear on screen. If you run the application and close the two child windows, the parent window is minimized to the task bar. If you comment out childWindow2.show(), run the application, and close the single child window, the parent window is not minimized to the taskbar.
I can add the following code to work around this problem:
childWindow1.Closing += delegate(object sender, CancelEventArgs ex)
{
(sender as Window).Owner = null;
};
but I don't want to use a hack like this, and I want to understand why this problem occurs.
Why does this happen?
This is a WPF undocumented feature(Bug)
This bug has been reported to Microsoft more than 7 years ago.
Modal dialog on top of non-modal window sends main window to back.
The WPF team has recently reviewed this issue and will not be
addressing this issue as at this time the team is focusing on the bugs
impacting the highest number of WPF developers.
Let's look at the behavior of this undocumented feature a bit.
It doesn't Minimize, just go one window behind (in debug mode, behind the visual studio window)
Steps to prove:
Run this application.
Minimize all other windows (eg: visual studio and all other windows). Keep only these three windows on the screen.
Close both children, parent is still in Normal State
Test this code for further proof:
StateChange wouldn't fire.
protected override void OnStartup(StartupEventArgs e)
{
var parentWindow = new Window() { Title = "Parent" };
parentWindow.StateChanged += (sender, ep)=>
{
var state = ((Window)sender).WindowState;
};
parentWindow.Show();
var childWindow1 = new Window { Owner = parentWindow, Title = "Child1" };
childWindow1.Show();
var childWindow2 = new Window { Owner = parentWindow, Title = "Child2" };
childWindow2.Show();
}
Being TopMost prevent this happening
If parent window is TopMost, this wouldn't happen. But this may not be an option in many cases.
parentWindow.Topmost = true;
Workaround
Activate the parent on child2 close.
childWindow2.Closed += (a, b) => { parentWindow.Activate(); };
This is due to the fact that you can't use the parent window once the child window is shown with the Owner set. Just try to access the parent window while the child is on the screen, and it won't let you, to see what i mean.
If you don't specify Owner then this behaviour doesn't happen.
I never worked out what is causing this to happen! In the end, I wrote this code that is called after any child window is closed:
// App inherits from Application, and has a Window property called MainWindow
// and a List<Window> property called OpenWindows.
if (!App.OpenWindows.Any())
App.ParentWindow.Activate();
So if the last child window is closed (making App.OpenWindows.Any() false) the parent window is activated. This does not result in flicker (the main window minimizing then maximizing, for instance.)
This isn't the best solution. I will not close this question in the hope that someone can explain why WPF has this functionality!

WPF window position

I have asked a question before about creating a child window here ... Now when I open child window, it doesn`t open centered to the parent window. How can I set it to open centered to the parent window?
This solution worked fine for me.
Here’s a method I’ve found for centering a window to either its parent or the main window for the application, in WPF. It’s not too different from how you do it in WinForms.
For the child window, set its WindowStartupLocation to “CenterOwner”. This will cause it to show in the center of the owning Window.
Collapse
<Window x:Class="WpfApplication1.TestChild"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestChild" Height="300" Width="300"
WindowStartupLocation="CenterOwner">
Now, all that’s left to do is set its owner before displaying it. If the code you’re using to display the window is running inside of a Window class, then you can just use this.
Collapse
TestChild testWindow = new TestChild();
testWindow.Owner = this;
testWindow.Show();
This isn’t always the case, however; sometimes, you need to display the child window from the code running on a page or a user control. In this case, you want the child window to be centered to the main window of the application.
Collapse
TestChild testWindow = new TestChild();
testWindow.Owner = Application.Current.MainWindow;
testWindow.Show();
Try this.
aboutWindow.WindowStartupLocation= WindowStartupLocation.CenterOwner ;
aboutWindow.ShowDialog(this);
You can try this:
AboutWindow window = new AboutWindow();
window.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
window.Owner = this;
window.ShowDialog();

How do you send information from one window to another in the same program?

In the program I am trying to build, I have a menu button that opens a second window. The user puts information into the second window, presses the "Done" button, and the information is transfered into the main window. The problem I am having is opening the second window. I have both windows build in xaml files in Visual Studio but I can't find a way to show the second window. Using "Window window = new Window" does not fit my needs because 1) I already have the second window built and 2) I have tried this and I cannot figure out how to add children to the window; there is no window.children nor any grid to put the children into. Thank you in advance!
Moments after I pressed post, I thought of something I hadnt tried:
"WindowAdd add = new WindowAdd; //WindowAdd being the second window
add.Show();"
This does exactly what I want it to do. The next problem I have is sending the information the TextBoxes into the MainWindow. I am thinking cookies might work but am unsure. Anyone have any thoughts? Thanks in advance!
You need to create the Window in code, but instead of doing:
Window window = new Window();
You should use:
Window2 window = new Window2(); // Assuming the window's class name is Window2
This will construct and initialize an instance of your new window class, defined in XAML. Once you've done this, you can open the window and you'll see all of your controls.

How do I focus a modal WPF Window when the main application window is clicked

I have my MainApplication Window that launches a new Window with .ShowDialog() so that it is modal.
UploadWindow uploadWindow = new UploadWindow();
uploadWindow.ShowDialog();
Now users are often leaving this window open and it can get lost under other windows. When the MainApplication is clicked you get an error-like beep and are unable to interact with it, so the modal window is blocking properly as expected, but it would be nice if the modal window was focused at this point to show the user it was still open.
Currently it just looks as if the MainApplication window has locked up.
Try setting the dialog's owner:
var uploadWindow = new UploadWindow();
uploadWindow.Owner = this;
uploadWindow.ShowDialog();
I have the problem, that I can't use this, if someone have the same problem, you can use
Window.GetWindow(this)
Since I am using MVVM, I'm not creating the code from the GUI. I used this.
var uploadWindow = new UploadWindow();
uploadWindow.Owner = Application.Current.MainWindow;
uploadWindow.ShowDialog();
If all of the above solutions tried and still facing the same problem
then here is your tested and verified solution
go to your window xaml and add
ResizeMode = "NoResize"
Nowadays you can just set Topmost = true
var uploadWindow = new UploadWindow();
uploadWindow.Topmost = true;

Categories

Resources