How to make Open/Save file dialog open on same monitor as app with multiple monitors
-
Friday, June 25, 2010 10:04 PM
For any custom dialog (form) in a WinForm application one can set its size and position before displaying it with code such as this:
form.StartPosition = FormStartPosition.Manual; form.DesktopBounds = MyWindowPosition;
This is particularly important when dealing with multiple monitors. Without such code, when you open a dialog from an application that you have opened on a second monitor, the dialog appears on the primary monitor. This presents a poor user experience.I would like to know how to do this for standard .NET dialogs, particularly OpenFileDialog and SaveFileDialog (which do not provide a StartPosition property).
I have been looking for a good solution to this for awhile, even posting on other forums some time ago, but have had no success resolving this question.
All Replies
-
Monday, June 28, 2010 2:46 AMModerator
Hi msorens,
What about showing the dialog like this?
OpenFileDialog openFileDlg = new OpenFileDialog();
openFileDlg.ShowDialog(this);
“this” refers to the parent form. The OpenFileDialog will always popup on the parent form. I do not have multiple screens to test it. Please test it and tell me if it works?
Sincerely,
Kira Qian
MSDN Subscriber Support in Forum
If you have any feedback on our support, please contact msdnmg@microsoft.com
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! -
Tuesday, June 29, 2010 5:45 PM
That is the obvious thing to try, of course, but it does not work. Here is a scenario where it fails:
- Run application.
- Invoke new OpenFileDialog().ShowDialog(this) to open dialog; the dialog appears on the same monitor as the application.
- Close dialog.
- Drag application window to different monitor.
- Invoke new OpenFileDialog().ShowDialog(this); dialog appears on original monitor.
Even using a fresh OpenFileDialog in step 5, there is still something persistent about the main app's original location. In contrast, the same test on a custom dialog window succeeds, where the custom dialog (form) has StartPosition and DesktopBounds set as in my original question. -
Wednesday, June 30, 2010 2:14 AMModerator
> Even using a fresh OpenFileDialog in step 5, there is still something persistent about the main app's original location.
In order to test your issue, I found a multi-monitor pc to do the test.
1. If you use a fresh Dialog to show. It appears on the secondary monitor when the parent form is there. If you try to drag the OpenFileDialog to the main monitor and close. The next time it will open in main monitor.
2. If you do not create a new instance of OpenFileDialog, it will remember the original location.
3. A standard Form does not like OpenFileDialog. It allows you to derive and change most property. The OpenFileDialog is not. It come from Windows system.
Sincerely,
Kira Qian
MSDN Subscriber Support in Forum
If you have any feedback on our support, please contact msdnmg@microsoft.com
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! -
Wednesday, June 30, 2010 2:55 PM
I think you are trying to say that the OpenFileDialog does not have the same properties as custom dialogs so the technique in my original question does not apply, which I already know. My original question was, and still is, to find another solution to the problem.
First, I will state that there should be a solution because if a piece of software does not do what a user reasonably expects then it has a defect that should be corrected. I maintain that if I move my application from monitor A to monitor B then bring up an OpenFileDialog, it is reasonable to assume the dialog will be on the same monitor.
Second, there are a variety of articles available on the web that customize the OpenFileDialog. My only problem is that from the several I have looked at it is not clear to me how to address my specific customization, i.e. open on the same monitor.
-
Thursday, July 01, 2010 1:57 AMModerator
Hi msorens,
> it is reasonable to assume the dialog will be on the same monitor.
I quite agree with that. But the situation is it already display on the same monitor as the form. Please new an instance when you want to show the OpenFileDialog. Do not use the original one. If the situation on your side is not the same as mine, could you please make a simple project to reproduce the issue?
Sincerely,
Kira Qian
MSDN Subscriber Support in Forum
If you have any feedback on our support, please contact msdnmg@microsoft.com
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! -
Thursday, July 01, 2010 3:37 PM
I suspect you did not try the test case I detailed in my June 29th reply. I am confident that if you had you would have seen the problem with your own test. Nevertheless, here is a complete program ready for testing and again here are the steps to show the problem:
- Run application.
- Press button to open dialog; the dialog appears on the same monitor as the application.
- Close dialog.
- Drag application window to different monitor.
- Press button to open dialog; dialog appears on original monitor.
using System; using System.Windows.Forms; namespace MultiMonitorTest { static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.Run(new Form1()); } } public class Form1 : Form { private System.ComponentModel.IContainer components = null; private System.Windows.Forms.Button button1; private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.button1 = new System.Windows.Forms.Button(); this.button1.Location = new System.Drawing.Point(86, 111); this.button1.Text = "button1"; this.button1.Click += new System.EventHandler(this.button1_Click); this.ClientSize = new System.Drawing.Size(356, 281); this.Controls.Add(this.button1); } public Form1() {InitializeComponent();} private void button1_Click(object sender, EventArgs e) { OpenFileDialog dlg = new OpenFileDialog(); dlg.ShowDialog(this); } } } -
Friday, July 02, 2010 1:41 AMModerator
I have already followed these steps to do the test before I post my reply. The result is
4. Drag application window to different monitor.
5. Press button to open dialog; dialog appears on different monitor.
The code is the same as yours. That’s why I said I cannot reproduce the issue.
Sincerely,
Kira Qian
MSDN Subscriber Support in Forum
If you have any feedback on our support, please contact msdnmg@microsoft.com
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! -
Saturday, July 03, 2010 9:39 AM
I suspect you did not try the test case I detailed in my June 29th reply. I am confident that if you had you would have seen the problem with your own test.
Please give some credit and show some respect for the people who are trying to help you here ...
I can confirm that the steps you described are not enough to reproduce the issue on my machine either. even with playing around, using the same instance of dialog, adding a main form which starts the other one ... nothing helped.
Did you have a chance to experience the same issue on another system, or have complaints from users ?
BTW, I've been testing on Windows Vista Business SP1 ...
Best regards,
Vladimir -
Tuesday, July 06, 2010 9:45 PM
Vladimir: You brought up a key point that I was about to comment on as well: the OS. My simple test fails on every machine I have tried--all are running XP. And I have tried compiling against .NET 2.0 and against .NET 3.5.
While I thought it a lot more likely that the .NET version might be a factor rather than the OS, apparently not.
Kira, what OS did you test with?
-
Wednesday, July 07, 2010 1:46 AMModerator
I use Win7 and Server 2008.
Sincerely,
Kira Qian
MSDN Subscriber Support in Forum
If you have any feedback on our support, please contact msdnmg@microsoft.com
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! -
Wednesday, July 07, 2010 3:28 PM
So my original issue still remains, with a slight revision:
How do I get OpenFileDialog and SaveFileDialog to always open on the same monitor as its parent app--from WinXP through Win7?
-
Thursday, July 08, 2010 1:26 AMModerator
Sorry, there is no solution for WinXP.
Sincerely,
Kira Qian
MSDN Subscriber Support in Forum
If you have any feedback on our support, please contact msdnmg@microsoft.com
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! -
Thursday, July 08, 2010 8:25 PM
If you are really really desperate you can resort to the Win32 API...
(Yes it's ugly but it works.)using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; using System.Runtime.InteropServices; namespace MultiMonitorTest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void OpenDialogButton_Click(object sender, EventArgs e) { // e.g. place over top of the main form Point myNewLocation = Location; myNewLocation.Offset(20, 20); OpenFileDialog dlg = new OpenFileDialog(); dlg.Title = "Open"; MoveDialogWhenOpened(dlg.Title, myNewLocation); dlg.ShowDialog(this); } private void SaveFileDialogButton_Click(object sender, EventArgs e) { // e.g. place over top of the main form Point myNewLocation = Location; myNewLocation.Offset(20, 20); SaveFileDialog dlg = new SaveFileDialog(); dlg.Title = "Save As"; MoveDialogWhenOpened(dlg.Title, myNewLocation); dlg.ShowDialog(this); } private void MoveDialogWhenOpened(String windowCaption, Point location) { Object[] argument = new Object[] { windowCaption, location }; BackgroundWorker backgroundWorker = new BackgroundWorker(); backgroundWorker.DoWork += new DoWorkEventHandler(MoveDialogThread); backgroundWorker.RunWorkerAsync(argument); } private void MoveDialogThread(Object sender, DoWorkEventArgs e) { const String DialogWindowClass = "#32770"; String windowCaption = (String)(((Object[])e.Argument)[0]); Point location = (Point)(((Object[])e.Argument)[1]); // try for a maximum of 4 seconds (sleepTime * maxAttempts) Int32 sleepTime = 10; // milliseconds Int32 maxAttempts = 400; for (Int32 i = 0; i < maxAttempts; ++i) { // find the handle to the dialog IntPtr handle = Win32Api.FindWindow(DialogWindowClass, windowCaption); // if the handle was found and the dialog is visible if ((Int32)handle > 0 && Win32Api.IsWindowVisible(handle) > 0) { // move it Win32Api.SetWindowPos(handle, (IntPtr)0, location.X, location.Y, 0, 0, Win32Api.SWP_NOSIZE | Win32Api.SWP_NOZORDER); break; } // if not found wait a brief sec and try again Thread.Sleep(sleepTime); } } } public class Win32Api { public const Int32 SWP_NOSIZE = 0x1; public const Int32 SWP_NOZORDER = 0x4; [DllImport("user32")] public static extern IntPtr FindWindow(String lpClassName, String lpWindowName); [DllImport("user32")] public static extern Int32 IsWindowVisible(IntPtr hwnd); [DllImport("user32")] public static extern Int32 SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, Int32 x, Int32 y, Int32 cx, Int32 cy, Int32 wFlags); } }- Marked As Answer by msorens Tuesday, July 13, 2010 6:13 PM
-
Tuesday, July 13, 2010 6:18 PMWell I would not quite characterize myself as desperate :-) regarding this; perhaps passionate: the situation that your code has remedied, Brett, is uglier than your code itself :-) so I consider it a net gain (i.e. I think it reflects poorly on an application that may have its open file dialog potentially a couple feet away on a second or third monitor. At least it apparently is not an issue on Windows 7... Thanks for your assistance!


