【发布时间】:2014-02-12 09:31:20
【问题描述】:
由于我的英文不好,我把我的问题简单解释一下,在这里贴一个代码sn-p来描述问题。
问题是我们的 winForm 应用程序中的多线程问题。我将逻辑简化为以下代码示例。
在测试代码中,mainForm中有1个mainForm Form1和一个名为“开始”的按钮。当用户单击该按钮时,将从 2 个后台线程显示两个表单 form2 和 form3。 form2 关闭后,Form1 将被触发关闭。但是这里显示了form3,所以我需要用户自己关闭form3。所以我处理了 form.Closing 事件并使用 Application.DoEvents() 让用户关闭 form3。它看起来很有效。但实际上,form3 可以接受用户的操作,但 form3 不会按预期关闭。
这里请解释一下为什么form3不能关闭以及如何修改代码使用户的关闭操作生效。
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace CloseFormFromMainThread
{
public partial class Form1 : Form
{
private Form2 _form2;
private Form2 _form3;
private SynchronizationContext _synchronizationContext;
public Form1()
{
InitializeComponent();
Closing += Form1Closing;
}
void Form1Closing(object sender, CancelEventArgs e)
{
while (_form3 != null)
{
Application.DoEvents();
Thread.Sleep(100);
}
}
private void ButtonStartClick(object sender, EventArgs e)
{
var thread = new Thread(StartForm3);
thread.Start();
var thread2 = new Thread(StartForm2);
thread2.Start();
}
private void StartForm3()
{
Thread.Sleep(200);
var action = new Action(() =>
{
_form3 = new Form2();
_form3.Text = "form 3";
_form3.ShowDialog();
_form3 = null;
});
ExecuteActionInUiThread(action);
}
private void Form1Load(object sender, EventArgs e)
{
_synchronizationContext = SynchronizationContext.Current;
}
private void StartForm2()
{
Thread.Sleep(500);
var action = new Action(() =>
{
_form2 = new Form2();
_form2.Text = "form 2";
_form2.ShowDialog();
Close();
});
ExecuteActionInUiThread(action);
}
private void ExecuteActionInUiThread(Action action)
{
var sendOrPostCallback = new SendOrPostCallback(o => action());
_synchronizationContext.Send(sendOrPostCallback, null);
}
}
}
【问题讨论】:
-
你为什么使用线程?一切似乎都在 UI 线程上运行?第 1 步是摆脱所有不必要的复杂性并删除线程。然后你就有机会看到你的程序真正做了什么。
-
真正的代码不应该需要 Thread.Sleep()。并且 GUI 始终是 1 个线程,否则不要尝试创建它。
-
@HenkHolterman:这行不通。 WinForms 不支持多线程。它只会崩溃。
-
这是一个非常简单的代码来描述我的问题。在我的应用程序中,UI 线程中有许多复杂的函数,这些函数会花费大量时间并阻塞用户的其他操作。我把函数移到了后台线程,但是代码中有一些UI操作,我使用synchronizationContext来同步主线程中的UI调用,比如form2和form3。有时,用户想关闭form2来退出我们的应用程序,我们需要用户先从其他功能关闭form3,然后关闭主窗体。我们不能在这里使用 Application.Exit。
-
@PMF:我就是这么说的,对吧?
标签: c# multithreading winforms synchronizationcontext