因为我知道由于UI和Worker线程之间的交互,不可能将winform加载到后台工作者的DoWork中,但是我找到了一种方法来实现这一点,我定义了另一个显示Form的线程,然后将该线程启动到背景工作者的DoWork . 它起作用了,我现在可以控制那个背景工作者的过程...但是我不确定它是否是一种安全的方法 . 我的简化计划是:命名空间WindowsFormsApplication1 {
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
void UI1()
{
using (Form2 f = new Form2())
f.ShowDialog();
}
Thread ui1;
private void Form1_Load(object sender, EventArgs e)
{
ui1 = new Thread(UI1);
Control.CheckForIllegalCrossThreadCalls = false;
temp.backgroundWorker1.DoWork+=new DoWorkEventHandler(backgroundWorker1_DoWork);
}
private void button1_Click(object sender, EventArgs e)
{
temp.backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100000;
progressBar1.Value = 0;
for (int i = 0; i < 100000; i++)
{
progressBar1.Value++;
if (i == 5000)
{
ui1.Start();
temp.backgroundWorker1.CancelAsync();
temp.ew.Reset();
}
if (temp.backgroundWorker1.CancellationPending)
temp.ew.WaitOne();
}
}
}
并在Form2中:private void button1_Click(object sender,EventArgs e){temp.ew.Set(); this.Close(); }
1 回答
在您的代码示例后更新了答案
首先,拥有多个UI线程或从不同线程访问UI是一个非常糟糕的主意 . 这是许多错误的来源,这些错误很难重现和调试 .
因此,永远不要在 生产环境 代码中使用
Control.CheckForIllegalCrossThreadCalls = false
.我将尝试给你一个代码示例(几乎)与你的相同,但没有任何第二个UI线程 .
Form2和与Form1的通信
这是我的代码
Form2
. 它使用Form1
Form1
可以订阅(如下所示),以便在点击Form2.button1
时获得通知 .Form1使用
BackgroundWorker
及其事件所以,有了
backgroundWorker1.ReportsProgress = true
,我表明这名 Worker 将要举起ProgressChanged
事件 . 关于ProgressChanged
事件的好处是,它在您的UI线程中执行 .当报告5000的进度时,我创建
Form2
的实例并将form2_ButtonClicked
方法注册为该实例的ButtonClicked
事件的处理程序 .然后我使用
Form.Show
而不是Form.ShowDialog
打开新的form2
,所以它不是模态的 .工作线程本身已重置
ew
,因此ew.WaitOne
现在将阻止,直到再次设置ew
. 这就是上面提到的事件处理程序form2_ButtonClicked
中发生的情况 .作为奖励,我在第一个表单中单击时禁用
button1
,并在后台工作程序完成时重新启用它,以便用户在第一个运行时无法启动另一个线程 . 如果您希望多个线程并行运行,则代码会变得复杂一些 . 但由于只有一个进度条,我假设一次只应该有一个进程 .我希望这个解释可以帮到你 . 我重复我的热爱阅读official documentation at MSDN!
历史完整性的原始帖子
backgroundWorker1_DoWork
方法实际上已经在与启动该后台工作程序的UI线程不同的线程中运行 .您正在启动另一个显示对话框的线程 . 最后,您可以直接在该后台工作程序中执行此操作:
这两种方式都很简单: to answer your question :您的解决方案是 as unsafe as 直接从后台工作人员打开表单!问题是, why 你想这样做吗?为什么你的新
Form2
应该在不同的线程中运行?如果您想要一个非模态窗口(以便您的用户可以切换到父窗口而不必关闭Form2
),请考虑使用Form.Show()而不是ShowDialog
.编辑:只是为了确定:在主UI线程中使用
Form.Show()
,而不是在后台工作程序中,而不是在其他线程中 .Form.Show()
立即返回,所以如果你在其中一个线程中调用它,这个线程将在之后终止并且可能也会关闭窗口 .