noel
noel

Reputation: 452

Windows form ALWAYS launches on the primary monitor

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!

Upvotes: 1

Views: 1874

Answers (2)

noel
noel

Reputation: 452

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.

Upvotes: 2

Wyck
Wyck

Reputation: 11770

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.

Upvotes: 1

Related Questions