0

What I'm trying to achieve is to show FirstForm during long operation. When this operation ends I'd like to close FirstForm and show SecondForm. Below is sample code: for my suprise Close is not working (both forms are visible).

using System;
using System.Windows.Forms;
using System.Threading.Tasks;

namespace WindowsFormsApplication1
{
static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FormMain());
    }
}

class FormMain : Form
{
    public FormMain()
    {
        var button = new Button() { Text = "test" };
        button.Click += (o, e) =>
        {
            var first = new FormFirst();
            Task.Factory.StartNew(() =>
            {
                ////some long operation...
            }).ContinueWith(t => {
                first.Close();
                var second = new FormSecond();
                second.ShowDialog();
            }, TaskScheduler.FromCurrentSynchronizationContext());
            first.ShowDialog();
        };

        Controls.Add(button);
    }
}

class FormFirst : Form
{
    public FormFirst() { Text = "First"; }
}

class FormSecond : Form
{
    public FormSecond() { Text = "Second"; }
}
}

I solved this using Form.Invoke but is this a proper way?:

var first = new FormFirst();
Task.Factory.StartNew(() =>
{
   ////some long operation...
   var created = new AutoResetEvent(first.IsHandleCreated);
   first.HandleCreated += (o1,e1) => created.Set();
   created.WaitOne();
   first.Invoke(new Action(() => first.Close()));
}).ContinueWith(t =>
{
    first.Close();
    var second = new FormSecond();
    ...
Michał Zych
  • 149
  • 1
  • 8

1 Answers1

0

Using invoke is the proper way to do it.

Since WinForms controls are not thread safe, this property was added to ensure that the only thread that can access a form's methods is the one it was created by. If the property is set to true, then calling a form's method directly from another thread does not work. Now, you could set it to false and go on with your life, however be aware that this exists for very good reasons.

Using Form.Invoke is the correct, thread-safe way to do what you're trying to achieve. If you want further explanation, you can refer to this MSDN page on creating thread-safe calls to WinForms controls. Also, if you're interested in finding out why its like this, user Adriano Repetti explained it really well in this answer.

Community
  • 1
  • 1
stelioslogothetis
  • 9,371
  • 3
  • 28
  • 53