none
backgroundwork的问题,死活搞不定了。求助 RRS feed

  • 问题

  • [C#.NET] 如何 使用 BackgroundWorker 多執行緒 / 跨執行緒 存取UI http://www.dotblogs.com.tw/yc421206/archive/2009/02/15/7174.aspx 

     

    我看这个文章,没看懂。。

     

    照样做了,但是运行不了。代码如下:

    int icount = 100000;
     string mystr;

    private delegate void myUICallBack(string mystr, Control ctl);
            private void myUI(string mystr, Control ctl)
            {
                if (this.InvokeRequired)
                {
                    myUICallBack myUpdate = new myUICallBack(myUI);
                    this.Invoke(myUpdate, mystr, ctl);
                }
                else
                {
                    ctl.Text = mystr;
                }
            }


    C#初学者,所以提的问题对各位前辈朋友来说可能很简单,也可能问法也不对,非常期待大家的回答……
    2010年11月23日 10:06

答案

  • 你好

    icount 只是一個optional Parameter 用來給 你 的

    for (int i = 1; i <= icount; i++) 使用的

    有關 使用 多執行緒 或者你可以參考以下URL

    VB.Net Use BackgroundWorker To Improved User Experience — VB.Net 使用 BackgroundWorker 增加使用者經驗上

    http://blog.sharechiwai.com/2010/09/vb-net-use-backgroundworker-to-improved-user-experience-vb-net-%E4%BD%BF%E7%94%A8-backgroundworker-%E5%A2%9E%E5%8A%A0%E4%BD%BF%E7%94%A8%E8%80%85%E7%B6%93%E9%A9%97%E4%B8%8A/

    VB.Net Threading —VB.Net 線程

    http://blog.sharechiwai.com/2010/09/vb-net-threading-vb-net-%E7%B7%9A%E7%A8%8B/

    Please correct me if my concept is wrong


    Chi
    2010年11月23日 11:12
    版主
  •  

    dear
    你说会失败的原因是UI卡住吗??如果是的话,原因是回报状态(backgroundWorker1_ProgressChanged)方法跟runsample方法暫停的时间一样,所以视觉上会觉得UI卡住,你可参考以下。

    1.runsample方法占停的时间要大于回报状态(backgroundWorker1_ProgressChanged),下面两行顺序最好不要调换。
    Application.DoEvents();
    Thread.Sleep(2);

        private void runsample(BackgroundWorker mywork)
        {
          mystr = "";
          for (int i = 1; i <= icount; i++)
          {
            try
            {
              mywork.ReportProgress(i);
              mystr = i.ToString();
            }
            catch (Exception ex)
            {
              MessageBox.Show(ex.ToString());
              break;
            }
          }
          Application.DoEvents();
          Thread.Sleep(2);
        }
    

    2.把回报回报状态(backgroundWorker1_ProgressChanged)的占停Thread.Sleep(1);拿掉

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
          try
          {
            this.progressBar1.Value = e.ProgressPercentage;
            //Thread.Sleep(1);
          }
          catch (Exception ex)
          {
            MessageBox.Show(ex.ToString());
    
          }
        } 
    

    以上选一种来跑跑看

     


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    2010年11月24日 2:09
  • 首先理清backgroudWorker1是怎么工作的。

    我觉得backgroudWorker是为了简化多线程的代码量而存在的一个控件,因为他只有三个Event处理函数,只要理解了原理就很容易使用

     

     

    1,private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 

    这个函数里面的所有动作,都是在单独一个线程里面执行的,是你真正想要做的处理。

    从这里面不能修改主线程界面。但是在这里可以调用backgroundWorker1.ReportProgress(百分比,具体信息)函数,把要在界面上显示的东西传送给第二个Event处理函数。


    2,private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)

    这个函数里面可以接收到上面ReportProgress()函数传送过来的百分比值和具体信息,显示在主界面上。

    除了ProgressBar之外,修改其他控件的值(比如用一个主界面上的Label显示信息),应该用delegate 。


    3,private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

    DoWork()结束之后,就进入这个函数,你可以做一些弹出Message或者关闭画面之类的处理。

     

    下面的两个属性设置,都不应该在DoWork里面做

                this.backgroundWorker1.WorkerReportsProgress = true;
                this.progressBar1.Maximum = icount;

     

    应该在设置完这些属性之后,再调用backgroundWorker1.RunWorkerAsync(),告诉backgroundWorker1,你可以开始执行DoWork()处理了

     

    格式有点乱,请凑合看吧:)


     

     

    2010年11月24日 2:39
  • dear,

    1.你抄范例程式时有注册事件吗?
    backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
    backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);

    2.使用backgroundWorker若会发生跨执行绪的问题,表示WorkerReportsProgress未设定为true,你观察你的mywork的WorkerReportsProgress应该是false,所以只要在传入runsample()前设定为true就好了,变更顺序试试

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
          this.backgroundWorker1.WorkerReportsProgress = true;
          this.progressBar1.Maximum = icount;
          runsample(sender as BackgroundWorker);
        }
    


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    2010年11月24日 18:27

全部回复

  • private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                runsample(sender as BackgroundWorker);
                this.backgroundWorker1.WorkerReportsProgress = true;
                this.progressBar1.Maximum = icount;
            }
    C#初学者,所以提的问题对各位前辈朋友来说可能很简单,也可能问法也不对,非常期待大家的回答……
    2010年11月23日 10:06
  • private void runsample(BackgroundWorker mywork)
            {
                mystr = "";
                for (int i = 1; i <= icount; i++)
                {
                    try
                    {
                        mywork.ReportProgress(i);
                        mystr = i.ToString();
                    }
                    catch(Exception ex)
                    {
                        MessageBox.Show(ex.ToString());
                        break;
                    }
                }
                Thread.Sleep(1);
                Application.DoEvents();
            }
    C#初学者,所以提的问题对各位前辈朋友来说可能很简单,也可能问法也不对,非常期待大家的回答……
    2010年11月23日 10:07
  • private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                try
                {
                    this.progressBar1.Value = e.ProgressPercentage;
                    Thread.Sleep(1);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                   
                }
            }  
    C#初学者,所以提的问题对各位前辈朋友来说可能很简单,也可能问法也不对,非常期待大家的回答……
    2010年11月23日 10:07
  • 当我点击按钮时 开始运行

     

    private void button1_Click(object sender, EventArgs e)
            {
                backgroundWorker1.RunWorkerAsync(icount);
            }

     

    我还不知道,为什么runworkerasync 中还有个icount


    C#初学者,所以提的问题对各位前辈朋友来说可能很简单,也可能问法也不对,非常期待大家的回答……
    2010年11月23日 10:08
  • 你好

    icount 只是一個optional Parameter 用來給 你 的

    for (int i = 1; i <= icount; i++) 使用的

    有關 使用 多執行緒 或者你可以參考以下URL

    VB.Net Use BackgroundWorker To Improved User Experience — VB.Net 使用 BackgroundWorker 增加使用者經驗上

    http://blog.sharechiwai.com/2010/09/vb-net-use-backgroundworker-to-improved-user-experience-vb-net-%E4%BD%BF%E7%94%A8-backgroundworker-%E5%A2%9E%E5%8A%A0%E4%BD%BF%E7%94%A8%E8%80%85%E7%B6%93%E9%A9%97%E4%B8%8A/

    VB.Net Threading —VB.Net 線程

    http://blog.sharechiwai.com/2010/09/vb-net-threading-vb-net-%E7%B7%9A%E7%A8%8B/

    Please correct me if my concept is wrong


    Chi
    2010年11月23日 11:12
    版主
  • 我还真觉得奇怪啊,我怎么看代码都没打错,可是,余小章前辈的代码,复制过来就能用。。。我晕啊。 。。总是提示跨线程 可是小章前辈程序里我没看出那个backgroundworker 中用到control 的invork 啊


    C#初学者,所以提的问题对各位前辈朋友来说可能很简单,也可能问法也不对,非常期待大家的回答……
    2010年11月23日 13:45
  • 你好

    icount 只是一個optional Parameter 用來給 你 的

    for (int i = 1; i <= icount; i++) 使用的

    有關 使用 多執行緒 或者你可以參考以下URL

    VB.Net Use BackgroundWorker To Improved User Experience — VB.Net 使用 BackgroundWorker 增加使用者經驗上

    http://blog.sharechiwai.com/2010/09/vb-net-use-backgroundworker-to-improved-user-experience-vb-net-%E4%BD%BF%E7%94%A8-backgroundworker-%E5%A2%9E%E5%8A%A0%E4%BD%BF%E7%94%A8%E8%80%85%E7%B6%93%E9%A9%97%E4%B8%8A/

    VB.Net Threading —VB.Net 線程

    http://blog.sharechiwai.com/2010/09/vb-net-threading-vb-net-%E7%B7%9A%E7%A8%8B/

    Please correct me if my concept is wrong


    Chi
    非常感谢,我看了下这个资料,很有用。只是我还没有找到为什么我的不能用 余小章前辈的很正常

    C#初学者,所以提的问题对各位前辈朋友来说可能很简单,也可能问法也不对,非常期待大家的回答……
    2010年11月23日 13:47
  •  

    dear
    你说会失败的原因是UI卡住吗??如果是的话,原因是回报状态(backgroundWorker1_ProgressChanged)方法跟runsample方法暫停的时间一样,所以视觉上会觉得UI卡住,你可参考以下。

    1.runsample方法占停的时间要大于回报状态(backgroundWorker1_ProgressChanged),下面两行顺序最好不要调换。
    Application.DoEvents();
    Thread.Sleep(2);

        private void runsample(BackgroundWorker mywork)
        {
          mystr = "";
          for (int i = 1; i <= icount; i++)
          {
            try
            {
              mywork.ReportProgress(i);
              mystr = i.ToString();
            }
            catch (Exception ex)
            {
              MessageBox.Show(ex.ToString());
              break;
            }
          }
          Application.DoEvents();
          Thread.Sleep(2);
        }
    

    2.把回报回报状态(backgroundWorker1_ProgressChanged)的占停Thread.Sleep(1);拿掉

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
          try
          {
            this.progressBar1.Value = e.ProgressPercentage;
            //Thread.Sleep(1);
          }
          catch (Exception ex)
          {
            MessageBox.Show(ex.ToString());
    
          }
        } 
    

    以上选一种来跑跑看

     


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    2010年11月24日 2:09
  • 首先理清backgroudWorker1是怎么工作的。

    我觉得backgroudWorker是为了简化多线程的代码量而存在的一个控件,因为他只有三个Event处理函数,只要理解了原理就很容易使用

     

     

    1,private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 

    这个函数里面的所有动作,都是在单独一个线程里面执行的,是你真正想要做的处理。

    从这里面不能修改主线程界面。但是在这里可以调用backgroundWorker1.ReportProgress(百分比,具体信息)函数,把要在界面上显示的东西传送给第二个Event处理函数。


    2,private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)

    这个函数里面可以接收到上面ReportProgress()函数传送过来的百分比值和具体信息,显示在主界面上。

    除了ProgressBar之外,修改其他控件的值(比如用一个主界面上的Label显示信息),应该用delegate 。


    3,private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

    DoWork()结束之后,就进入这个函数,你可以做一些弹出Message或者关闭画面之类的处理。

     

    下面的两个属性设置,都不应该在DoWork里面做

                this.backgroundWorker1.WorkerReportsProgress = true;
                this.progressBar1.Maximum = icount;

     

    应该在设置完这些属性之后,再调用backgroundWorker1.RunWorkerAsync(),告诉backgroundWorker1,你可以开始执行DoWork()处理了

     

    格式有点乱,请凑合看吧:)


     

     

    2010年11月24日 2:39
  • 谢谢小章哥, 失败指 显示不能跨线程操作。

     

    然后我加了条Control.CheckForIllegalCrossThreadCalls = False 好像,然后能执行了。后来,我把这条注释掉了,可是还能执行。真奇怪啊,不知道怎么回事

     

    UI卡的话,我把change后,sleep 去掉就行了。


    C#初学者,所以提的问题对各位前辈朋友来说可能很简单,也可能问法也不对,非常期待大家的回答……
    2010年11月24日 12:51
  • 感谢cs.liwei

    this.backgroundWorker1.WorkerReportsProgress = true;
    this.progressBar1.Maximum = icount;


    这两个为什么不能放这里啊?不解。

    this.backgroundWorker1.WorkerReportsProgress = true; 这个backgroundworker 的属性里直接设置, 但是 下面那个 this.progressBar1.Maximum = icount;如果icount是动态生成的话,另外好像没地方放啊



    C#初学者,所以提的问题对各位前辈朋友来说可能很简单,也可能问法也不对,非常期待大家的回答……
    2010年11月24日 12:56
  • dear,

    1.你抄范例程式时有注册事件吗?
    backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
    backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);

    2.使用backgroundWorker若会发生跨执行绪的问题,表示WorkerReportsProgress未设定为true,你观察你的mywork的WorkerReportsProgress应该是false,所以只要在传入runsample()前设定为true就好了,变更顺序试试

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
          this.backgroundWorker1.WorkerReportsProgress = true;
          this.progressBar1.Maximum = icount;
          runsample(sender as BackgroundWorker);
        }
    


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    2010年11月24日 18:27
  • 谢谢。明白了
    C#初学者,所以提的问题对各位前辈朋友来说可能很简单,也可能问法也不对,非常期待大家的回答……
    2010年11月25日 2:22