【问题标题】:Closing the Form opened in another thread关闭在另一个线程中打开的表单
【发布时间】:2015-06-14 00:02:18
【问题描述】:

我的 Winforms C# 应用程序遇到了一些问题。 我希望在主线程中的一些操作完成后关闭名为Popup 的表单。问题是跨线程表单关闭导致的异常。

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
}

我一直在尝试使用各种工具,例如LoginProcess.Abort()Popup.Dispose() 使其正常工作,但即使应用程序在运行时环境中工作,由于抛出异常,它仍然不稳定。 如有任何帮助,我将不胜感激,对于问题描述中的含糊之处,我深表歉意。

【问题讨论】:

  • 维护具有多个 UI 线程的应用程序是一种残酷的惩罚,我不希望我最大的敌人受到惩罚。帮自己一个忙,只需将您的应用程序限制为恰好 1 个 UI 线程。让 UI 线程完成所有 UI 工作,并在非 UI 线程中完成任何长时间运行的非 UI 工作。

标签: c# multithreading winforms


【解决方案1】:

为什么不让 UI 线程执行诸如打开和关闭表单之类的 UI 工作,并派生其他线程(或后台工作程序或异步任务)来执行其他工作?

IMO,让其他线程尝试与 UI 线程上的元素进行交互(例如,让后台线程直接设置标签的文本或类似的)正在请求心痛。

如果您只是必须保持您的代码不变,那么您可以做一件相当简单的事情。在 Popup 中,添加一个默认为 true 的静态布尔值。同样在 Popup 中,添加一个计时器任务,每 X 毫秒检查一次该布尔值的状态。如果它发现该值已设置为 false,则让 Popup 告诉自己在该计时器滴答内关闭。

我并不喜欢这种设计,但它可能看起来像:

 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();
        }

    }

然后,从另一个线程,当您希望 Popup 关闭时,调用

Popup.StayVisible = false;

更好的是,您可以触发 Popup 接收到的事件,以便它可以自行关闭。由于您打算使用多个线程,因此您必须处理raising events cross-thread

【讨论】:

    猜你喜欢
    • 2013-08-21
    • 2017-02-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-02
    • 1970-01-01
    • 2017-07-06
    • 2016-06-03
    • 1970-01-01
    相关资源
    最近更新 更多