Question

On the code below when the FormWaitingForm is called from the UI thread via buttonBusy_Click, formWaitingForm loads in the center of the main form as expected. However when called from the BackgroundWorker via buttonBusyWorkerThread_Click, it loads in the center of the PC screen. How can I fix this ?

public partial class Form1 : Form
{
    WaitingForm formWaitingForm;
    BackgroundWorker bw = new BackgroundWorker(); // Backgroundworker
    public Form1()
    {
        InitializeComponent();
        // Define event handlers
        bw.DoWork += new DoWorkEventHandler(ProcessTick);
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
    }

    private void buttonBusy_Click(object sender, EventArgs e)
    {
        // This starts in the center of the parent as expected
        System.Threading.Thread.Sleep(2000);
        formWaitingForm = new WaitingForm();
        formWaitingForm.StartPosition = FormStartPosition.CenterParent;
        formWaitingForm.ShowDialog();
    }

    private void buttonBusyWorkerThread_Click(object sender, EventArgs e)
    {
        // This does not start in the center of the parent
        bw.RunWorkerAsync(); // starts the background worker
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    { }

    private void ProcessTick(object sender, DoWorkEventArgs e)
    {
        // This does not start in the center of the parent
        System.Threading.Thread.Sleep(2000);
        formWaitingForm = new WaitingForm();
        formWaitingForm.StartPosition = FormStartPosition.CenterParent;
        formWaitingForm.ShowDialog();
    }
}
Was it helpful?

Solution

FormStartPosition.CenterParent applies to the parent of MDI forms, not to the owner form. Therefore it will have no effect on non-MDI forms.

You can use these extension methods to open a form centerd to its owner form:

public static void ShowCentered(this Form frm, Form owner)
{
    Rectangle ownerRect = GetOwnerRect(frm, owner);
    frm.Location = new Point(ownerRect.Left + (ownerRect.Width - frm.Width) / 2,
                             ownerRect.Top + (ownerRect.Height - frm.Height) / 2);
    frm.Show(owner);
}

public static void ShowDialogCentered(this Form frm, Form owner)
{
    Rectangle ownerRect = GetOwnerRect(frm, owner);
    frm.Location = new Point(ownerRect.Left + (ownerRect.Width - frm.Width) / 2,
                             ownerRect.Top + (ownerRect.Height - frm.Height) / 2);
    frm.ShowDialog(owner);
}

private static Rectangle GetOwnerRect(Form frm, Form owner)
{
    return owner != null ? owner.DesktopBounds : Screen.GetWorkingArea(frm);
}

Use it like this:

formWaitingForm.ShowDialogCentered(owner);

OTHER TIPS

Do not call it from a non-ui thread. Any windows based UI 101: only the creating thread can change the object.

in the background thread, use Invoke to invoke back into the UI thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top