如何从后台工作者运行另一个后台工作者运行Windows窗体?

时间:2015-12-03 08:26:47

标签: c# winforms

这是解决方案的简化计划: 由于某些原因,我需要通过另一个背景工作者运行的后台工作程序运行Windows窗体,当新的窗体加载时,旧的后台工作者必须暂停。我写这样的代码:

创建一个名为:temp

的类
public class temp
{
    static public BackgroundWorker backgroundWorker1 = new BackgroundWorker() { WorkerSupportsCancellation = true };
    static public EventWaitHandle ew = new EventWaitHandle(false, EventResetMode.ManualReset);
    static public BackgroundWorker back = new BackgroundWorker() { WorkerSupportsCancellation = true };   
}

form1的代码是:

namespace WindowsFormsApplication1
{

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {

       Control.CheckForIllegalCrossThreadCalls = false;
       temp.backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
        temp.back.DoWork += new DoWorkEventHandler(back_DoWork);          
    }

    void back_DoWork(object sender, DoWorkEventArgs e)
    {
        Form2 f = new Form2();
        f.Show();
    }
    private void button1_Click(object sender, EventArgs e)
    {

        temp.backgroundWorker1.RunWorkerAsync();

    }

   private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {

            temp.back.RunWorkerAsync();

            if (temp.backgroundWorker1.CancellationPending)
               temp.ew.WaitOne();
    }

   }
}

并且form2的代码在这里:

namespace WindowsFormsApplication1
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }



    private void Form2_Load(object sender, EventArgs e)
    {

     temp.backgroundWorker1.CancelAsync();
     temp.ew.Reset();
    }

   }
}

通过单击form1中的button1运行temp.backgroundworker1然后在temp.backgroundworker1的DoWork中运行temp.back然后运行FORM2 LOADS但FORM2挂起并且成为无用的,你不能再使用它了。 我哪里错了? 我要执行的整个计划是: 我们有一个For循环来处理DataGridView的每一行。 每次在某一点上,另一个窗口打开 并且它会停止循环,直到用户插入信息然后单击“确定”按钮,windowsform关闭并且循环继续工作。我不知道该怎么做.......

即使我不像下面的代码那样取消form2load中temp.backgroundworker的工作,Form2也没用了

private void Form2_Load(object sender, EventArgs e)
    {   


    }

1 个答案:

答案 0 :(得分:0)

不要在工作线程中使用任何UI操作(DoWork方法)。也许这就是为什么你设置CheckForIllegalCrossThreadCalls属性,但你的应用程序无法正常工作只是在附加调试器时抑制错误。

请参阅我的回答here以正确使用BackgroundWorker(关于取消,但您可以在UI和工作线程中查看操作)。

在这种特殊情况下,您可以使用类似的volatile bool来签署可以显示表单的UI线程。或者,如果要在线程之间发送不同的消息,请使用ConcurrentQueue<T>来编写和读取消息:

public partial class Form1 : Form
{
    private enum Message
    {
        ShowForm2,
        SuspendWork,
        ResumeWork,
        FinishWorker1
        // ... and whatever you want
    }

    private Timer timer;
    private ConcurrentQueue<Message> messagesToUI = new ConcurrentQueue<Message>();
    private ConcurrentQueue<Message> messagesToWorker = new ConcurrentQueue<Message>();

    public Form1()
    {
        InitializeComponent();
        timer = new Timer(this);
        timer.Interval = 10;
        timer.Tick += PollUIMessages;
        timer.Enabled = true;
    }

    void PollUIMessages(object sender, EventArgs e)
    {
        // do we have a new message?
        Message message;
        if (messagesToUI.TryDequeue(out message))
        {
            switch (message)
            {
                case Message.ShowForm2:
                    Form2 f = new Form2();
                    f.Show();
                    // todo: in Form2.Close add a Resume message to the messagesToWorker
                    break;

                // ... process other messages
            }
        }
    }

    void back_DoWork(object sender, DoWorkEventArgs e)
    {
        // Here you are in the worker thread. You can send a message to the
        // UI thread like this:
        messagesToUI.Enqueue(Message.ShowForm2);

        bool isWorking = true;

        // and here you can poll the messages to the worker thread
        while (true)
        {
            Message message;
            if (!messagesToWorker.TryDequeue(out message))
            {
                // no message: idle or work
                if (isWorking)
                    DoSomeWork(); // do whatever you want
                else
                    Thread.CurrentThread.Sleep(10);
                continue;
            }

            switch (message)
            {
                case Message.FinishWorker1:
                    // finishing the worker: jumping out
                    return;
                case Message.SuspendWork:
                    isWorking = false;
                    break;
                case Message.ResumeWork:
                    isWorking = true;
                    break;
            }
        }
    }