1

I support a desktop application that is written in C# and runs on windows forms. The application has a number of pop up forms (usually launched by clicking on a button), throughout the application. I have a request from the users to allow for them to choose which monitor they want the application to launch from (by default) and to save a store that information. With the Covid-19 pandemic, my company is in a situation where a lot of employees are working from home. A typical setup is a user with a laptop, probably plugged into a universal docking station, and there is a 2nd monitor attached. The users want the application to launch on the 2nd monitor versus the primary monitor (which is the laptop's monitor).

I seem to be running into issues when I set the default monitor to the 2nd (non-primary) monitor. Most of the forms will launch from the secondary monitor, however, not ALL of the forms will launch from the secondary monitor. It's a mystery to me at this point, hence this post. For example, I have the exact same code for two different forms that launch off a given form. One will launch on the current monitor (the second monitor). The other form will insist on launching on the primary monitor. Here is the code that I've tried.

//above this point, I'm passing in parameters
var screen = Screen.FromPoint(Cursor.Position);
myform.StartPosition = FormStartPosition.Manual;
myform.Left = screen.Bounds.Left + screen.Bounds.Width / 2 - myform.Width / 2;
myform.Top = screen.Bounds.Top + screen.Bounds.Height / 2 - myform.Height / 2;

Stepping through the code, here is what I see when I hover over fields in my code:

screen- {Bounds = {{X=1600,Y=0,Width=1440,Height=900}} WorkingArea = {{X=0,Y=0,Width=0,Height=0}} Primary = false DeviceName = "\\\\.\\DISPLAY7"}

That is definitely screen #2.

myform.Left = 1988
myform.Top = 237

Again, should have launched on screen #2.

I've also tried (instead of those 4 lines of code):

StartPosition = FormStartPosition.Manual;
OpusForms.fProductDetailForm.Location = Screen.AllScreens[getIndexofSelectedMonitor()].WorkingArea.Location;

getIndexofSelectedMonitor() is a function that I built to retrieve the index of the saved monitor (1 in this case).

I also tried hard coding the solution:

myform.StartPosition = FormStartPosition.Manual;
myform.Location = Screen.AllScreens[1].WorkingArea.Location;

And then below each of the 3 segments, I launch the new form with:

myform.ShowDialog();

In all cases, the form insists on launching on the primary monitor, and I'm not sure why. Any help is appreciated!

noel
  • 383
  • 4
  • 18
  • Have you tried changing the primary monitor to confirm that it indeed follows the primary monitor? Just curious. – Doug Dawson Jun 15 '20 at 18:43
  • Is the form you end up showing the same form as the one you repositioned? Show the code that creates myform and the code that shows it. Tell us what class that code is in – Caius Jard Jun 15 '20 at 18:46
  • @DougDawson If I change the default monitor to be the primary monitor (the laptop monitor), everything works perfectly. It's when I test using the 2nd monitor as the default that I notice not all forms work the same way, yet it's the same code. – noel Jun 15 '20 at 19:08
  • So essentially, some (but not all) of the forms insist on launching on the primary monitor, regardless of me telling it to launch on the secondary monitor. – noel Jun 15 '20 at 20:33
  • Check this out: [Using SetWindowPos with multiple monitors](https://stackoverflow.com/a/53026765/7444103). Make your app DpiAware, then verify the VirtualScreen properties. Use one of the methods described to get the Screens coordinates and the Monitor where the Form is actually shown or where you want to show it. -- Your `\\.\DISPLAY7` (Screen #2 ?) has an interesting WorkingArea. – Jimi Jun 16 '20 at 02:41
  • It's a laptop plugged into a Universal Docking Station. It seems to give a different number to the second monitor when I unplug it/plug it back in. The laptop monitor is always \\.\DISPLAY1, but the number for the 2nd monitor varies. – noel Jun 17 '20 at 00:24

2 Answers2

2

I'm answering my own question here. Wyck is asking the correct question above to post the complete form that reproduces the behavior. My problem with posting all of the code is that it's a lot of code (this application has existed for 20 years). So, I did the next best thing and I stepped through each and every line of the code. What I found is when the new form was loading, one of my predecessors had a method called CenterForm() that was overriding my code and placing the form on the primary screen.

I learned two lessons here. 1) always look at the complete code. In my case, the problem was downstream of where I was I had set my focus. 2) you really don't need all of the code above the make the form appear on a different monitor. You should simply be able to control this by the StartPosition "CenterParent" setting. Once I eliminated all of the other code, that's the only thing that I had to set on each form.

noel
  • 383
  • 4
  • 18
  • Thanks for the acknowledgement. I often find that writing a fully detailed question and carving it down to a minimal / self-contained repro can be just as effective as debugging with a debugger. Looks like you learned valuable lessons. Glad you're up and running again. – Wyck Jun 18 '20 at 18:54
1

This code works for me:

Just create a new Windows Forms application, then replace the Form1 code as follows:

public partial class Form1 : Form
{
    FlowLayoutPanel flowLayoutPanel1;

    public Form1()
    {
        InitializeComponent();

        flowLayoutPanel1 = new FlowLayoutPanel();
        flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
        Controls.Add(flowLayoutPanel1);
        foreach (var screen in Screen.AllScreens)
        {
            Button button = new Button();
            button.Size = new Size(128, 64);
            button.Text = screen.DeviceName;
            button.Click += (object sender, EventArgs e) =>
            {
                Form form = new Form();
                form.Text = screen.DeviceName;
                form.StartPosition = FormStartPosition.Manual;
                form.Bounds = screen.Bounds;
                form.Show();
            };
            flowLayoutPanel1.Controls.Add(button);
        }
    }
}

This will create an application that creates a button for each Screen you have, named according to the device name. Clicking the button will create a default blank form on that screen.

The trick is to set the form.Bounds and to set the form.StartPosition to FormStartPosition.Manual.

You could also set your form's WindowState to WindowState.Maximized if you so desire.

Wyck
  • 10,311
  • 6
  • 39
  • 60
  • Thanks for the reply. I tried a version of your solution mixed with my original code. Bounds seemed to be the one piece that I didn't have. When I set myform.Bounds = screen.Bounds, what I got was a larger form on the wrong screen, so same problem unfortunately. – noel Jun 15 '20 at 20:45
  • Intriguing! Perhaps you can share your desktop settings with us? Exactly how many screens, their resolutions and placement. And whether you are using anything like NVIDIA's mosaic mode (to make multiple monitors work like one according to windows). And can you be much more specific about "larger" and "wrong"? How much larger? Which screen? Does my code fail in a blank application too or only when "mixed with your original code"? Because it's working fine for me. So there's a mystery to be solved, for sure. Disclose as many details as you can in your question. – Wyck Jun 16 '20 at 13:53
  • it's a laptop plugged into a universal docking station. The universal docking station has a mouse, keyboard, and a monitor connected to it. Regarding: the 2 monitors under display settings- the laptop is the monitor on the left and the 2nd monitor is the monitor on the right. – noel Jun 17 '20 at 00:26
  • @noel I can't reproduce your results at all. Can you help me reproduce your problem? Post a complete Form1.cs that reproduces the behaviour you are seeing. – Wyck Jun 17 '20 at 13:53