C# 将UI线程运行到后台工作线程中

C# 将UI线程运行到后台工作线程中,c#,multithreading,winforms,thread-safety,backgroundworker,C#,Multithreading,Winforms,Thread Safety,Backgroundworker,据我所知,由于UI和工作线程之间的交互,无法将winform加载到backgroundworker的DoWork中, 但我找到了一种方法,我定义了另一个显示表单的线程,然后将该线程引入backgroundworker的DoWork中。 它成功了,我现在可以控制后台工作人员的进程。。。但我不确定这是否是一种安全的方法。我的简化计划是: namespace WindowsFormsApplication1 { public partial class Form1 : Form {

据我所知,由于UI和工作线程之间的交互,无法将winform加载到backgroundworker的DoWork中, 但我找到了一种方法,我定义了另一个显示表单的线程,然后将该线程引入backgroundworker的DoWork中。 它成功了,我现在可以控制后台工作人员的进程。。。但我不确定这是否是一种安全的方法。我的简化计划是:

namespace 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();
            }     
       }
    }
在代码示例之后更新了答案 首先,拥有多个UI线程或从不同线程访问UI是一个非常糟糕的想法。这是许多错误的来源,这些错误很难再现和调试

因此,在生产代码中不应使用设置
Control.CheckForIllegalCrossThreadCalls=false

我将尝试给你一个代码示例,它做(几乎)与你的相同的事情,但没有任何第二个UI线程

表格2和与表格1的沟通 这是我为您的
表单2
编写的代码。它使用
Form1
可以订阅的
EventHandler
(如下所示)在单击
Form2.button1
时获得通知

使用“BackgroundWorker”及其事件的Form1 回答您的问题的两种方法都是terrbile和:您的解决方案与直接从后台工作人员打开表单一样不安全!问题是,为什么要这样做?为什么新的
表单2
应该在不同的线程中运行?如果你想要一个非模态窗口(如果你的用户可以切换到父窗口,而不必关闭你的代码> Frave),可以考虑使用“<代码>显示对话框< /C>”。


编辑:只是为了确保:在主UI线程中使用
Form.Show()
,而不是在后台工作线程和其他线程中
Form.Show()
会立即返回,因此如果您在其中一个线程中调用它,该线程将在之后终止,并且可能也会关闭窗口。

这是造成灾难的最佳方法。为什么不使用BackgroundWorker来更新“正常”UI线程(因为这已经为您完成了)?“正常”UI线程是什么意思?我现在还没有访问visual studio righ,但整个计划是:backgroundworker的过程停止,直到另一个表单打开,用户插入信息并按下按钮,新表单关闭,backgroundworker继续工作。。。。所以我需要另一个表单,在进程停止时加载我们的计划。如果在后台处理过程中需要用户的输入,则需要将流程拆分为可以独立执行的块。整个计划是:后台工作人员的流程停止,直到另一个表单打开,用户插入信息并按下按钮,新表单关闭,backgroundworker继续工作。。。。所以我需要另一个表单,在进程停止时加载,我找不到一个安全的方法来进行加载,很抱歉,但是从这个评论中,我只得到了一个关于你想要实现什么的想法,但是听起来好像有一个很大的误解和设计缺陷。如果您能更详细地解释(并显示代码)您正在尝试做什么,我们可以更好地帮助您。从你到目前为止所写的内容来看,我仍然相信不需要在另一个线程上创建表单。我将在第二天再次在办公桌上编辑我的答案(现在在手机上书写)。我强烈建议阅读msdn中后台工作人员的官方文档!特别是像
ProgressChanged
事件、
ReportProgressChanged
CancelAsync
等关键字。。。我仍然认为没有必要在另一个线程中启动第二个表单。@Hnz Done。更新了我的答案。
        private void button1_Click(object sender, EventArgs e)
        {
            temp.ew.Set();
            this.Close();
        }
public partial class Form2 : Form
{
  public Form2()
  {
    InitializeComponent();
  }

  public event EventHandler ButtonClicked;
  protected virtual void OnButtonClicked()
  {
    EventHandler handler = ButtonClicked;
    if (handler != null) handler(this, EventArgs.Empty);
  }

  private void button1_Click(object sender, EventArgs e)
  {
    OnButtonClicked();
    Close();
  }
}
public partial class Form1 : Form
{
  private readonly BackgroundWorker backgroundWorker1 = new BackgroundWorker();
  private readonly ManualResetEvent ew = new ManualResetEvent(true);

  public Form1()
  {
    InitializeComponent();

    // this can all be done in designer too
    backgroundWorker1.WorkerReportsProgress = true;
    backgroundWorker1.DoWork += backgroundWorker1_DoWork;
    backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
    backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;

    progressBar1.Minimum = 0;
    progressBar1.Maximum = 10000;
    progressBar1.Value = 0;
  }

  private void button1_Click(object sender, EventArgs e)
  {
    button1.Enabled = false;
    ew.Set();
    backgroundWorker1.RunWorkerAsync();
  }

  private void form2_ButtonClicked(object sender, EventArgs e)
  {
    ew.Set();
  }

  private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
  {
    for (int i = 0; i < 10000; i++)
    {
      if (i == 5000) ew.Reset();
      backgroundWorker1.ReportProgress(i);
      ew.WaitOne();
    }
  }
  private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
  {
    progressBar1.Value = e.ProgressPercentage;
    if (e.ProgressPercentage != 5000) return;
    Form2 form2 = new Form2();
    form2.ButtonClicked += form2_ButtonClicked;
    form2.Show();
  }
  private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  {
    button1.Enabled = true;
  }
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
  using (Form2 f = new Form2())
    f.ShowDialog();
}