【问题标题】:How to run a windows form from a backgroundworker runnig through another backgroundworker?如何从通过另一个后台工作人员运行的后台工作人员运行 Windows 窗体?
【发布时间】:2015-12-03 17:13:35
【问题描述】:

这是解决方案的简化计划: 由于某些原因,我需要通过由另一个后台工作程序运行的后台工作程序运行 Windows 窗体,当新的 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 加载,但 FORM2 挂起并变得无用,您不能再使用它了。 我哪里错了? 我要执行的整个计划是: 我们有一个处理 DataGridView 每一行的 For 循环。 每次在某一点,另一个窗体打开 它会停止循环,直到用户插入信息然后单击“确定”按钮,windowsform 关闭并且循环继续工作。我不知道该怎么办.......

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

private void Form2_Load(object sender, EventArgs e)
    {   


    }

【问题讨论】:

    标签: c# winforms


    【解决方案1】:

    不要在工作线程中使用任何 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;
                }
            }
        }
    

    【讨论】:

    • 我没有得到你所做的,因为我是 C# 中的新手,但我做了另一个它工作的代码....我定义了一个显示 Windows 窗体的新线程:void UI() { 使用 (Form2 f = new Form2()) f.ShowDialog(); } 线程 ui = 新线程(UI);并从 temp.backgroundworker 的 DoWork 运行它,现在我可以从 Form2 控制 temp.backgroundworker 的进程......看起来是正确的,但我不知道在其中使用线程是常见的还是正确的这样……
    • 如果显式启动线程,则无需使用BackgroundWorker。另一方面,仍然不允许您从外部线程访问控件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多