-4

I'm getting some troubles with my Winforms C# app. I wish to make form named Popup closing after some operations in main thread are done. The problem is an exception caused by cross-thread form closing.

private void loginButton_Click(object sender, EventArgs e)
{
    LoginProcess.Start();    // Running Form.show() in new thread
    ActiveAcc.IsValid = false;
    ActiveAcc.Username = userBox.Text;

    try
    {
        LoginCheck(userBox.Text, passBox.Text);
    }
    catch (IOException)
    {
        MessageBox.Show("..");
        return;
    }
    catch (SocketException)
    {
        MessageBox.Show("..");
        return;
    }

    if (ActiveAcc.IsValid)
    {
        MessageBox.Show("..");
        Close();
    }
    else
    {
        Popup.Close();      // Error caused by closing form from different thread
        MessageBox.Show("");
    }
}

public Login()             // 'Main' form constructor
{
    InitializeComponent();

    ActiveAcc = new Account();
    Popup = new LoginWaiter();
    LoginProcess = new Thread(Popup.Show);      //Popup is an ordinary Form
}

I've been trying to use various tools such as LoginProcess.Abort() or Popup.Dispose() to make it work properly, but even if app is working on runtime environment its still unstable due to Exceptions which are thrown. I would be grateful for any help, and I am sorry for ambiguities in issue describing.

John Odom
  • 1,189
  • 2
  • 20
  • 35
baka1408
  • 433
  • 4
  • 21
  • Look at the following to get an idea: http://stackoverflow.com/questions/782274/using-c-sharp-methodinvoker-invoke-for-a-gui-app-is-this-good and alternatively https://msdn.microsoft.com/en-us/library/system.windows.forms.methodinvoker(v=vs.110).aspx – James Shaw Apr 08 '15 at 20:25
  • 2
    Maintaining an application with multiple UI threads is a cruel punishment that I wouldn't wish upon my worst enemies. Do yourself a favor and simply limit your application to exactly 1 UI thread. Have the UI thread do all UI work, and do any long running non-UI work in non-UI threads. – Servy Apr 08 '15 at 20:39

1 Answers1

1

Why don't you let the UI thread do UI stuff like opening and closing Forms, and spawn the other thread (or background worker, or async task) to do the other stuff?

IMO, having other threads attempt to interact with elements on the UI thread (e.g., have a background thread directly set the text of a label or some such) is asking for heartache.

If you simply must keep your code as is, here is a fairly simple thing you could do. In Popup, add a static bool that defaults to true. Also in Popup, add a timer task that once every X milliseconds checks the status of that boolean. If it finds that the value has been set to false, let Popup tell itself to close within that timer tick.

I'm not crazy about this design, but it could look something like:

 public partial class Popup : Form
    {
        public static bool StayVisible { get; set; }

        private System.Windows.Forms.Timer timer1;

        public Popup()
        {
            StayVisible = true;
            this.timer1.Interval = 1000;
            this.timer1.Tick += new System.EventHandler(this.timer1_Tick);

            InitializeComponent();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (!StayVisible) this.Close();
        }

    }

Then, from another thread, when you want Popup to close, call

Popup.StayVisible = false;

Better yet, you would fire an event that Popup would receive so that it could close itself. Since you intend to use multiple threads, you'll have to deal with raising events cross-thread.

Community
  • 1
  • 1
Gojira
  • 2,941
  • 2
  • 21
  • 30