2012-06-26 231 views
1

我有一个代码,其是这样的:如何避免GUI冻结?

private void testToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    toolStripStatusLabel1.Text = " Device Testing..."; 

    positive = false; 

    clearsensors_gui(); 
    datarec = false; 
    cmd = 04; 
    datarec = serialport_FT(0, 1); 

    if (datarec) 
    { 
     char ab = Convert.ToChar(rec_data[1]); 
     //MessageBox.Show("\n" + ab + "\n"); 
     int cab = Convert.ToInt16(ab); 
     int cabc1 = cab & 1; 
     int cabc2 = cab & 2; 
     int cabc3 = cab & 4; 
     int cabc4 = cab & 8; 
     int cabc5 = cab & 16; 
     int cabc6 = cab & 32; 

     if (cabc1 == 1) 
      ovalShape1.FillColor = Color.Green; 
     else 
      ovalShape1.FillColor = Color.Red; 

     if (cabc2 == 2) 
      ovalShape2.FillColor = Color.Green; 
     else 
      ovalShape2.FillColor = Color.Red; 

     if (cabc3 == 4) 
      ovalShape3.FillColor = Color.Green; 
     else 
      ovalShape3.FillColor = Color.Red; 

     if (cabc4 == 8) 
      ovalShape4.FillColor = Color.Green; 
     else 
      ovalShape4.FillColor = Color.Red; 

     if (cabc5 == 16) 
      ovalShape5.FillColor = Color.Green; 
     else 
      ovalShape5.FillColor = Color.Red; 

     if (cabc6 == 32) 
      ovalShape6.FillColor = Color.Green; 
     else 
      ovalShape6.FillColor = Color.Red; 

     toolStripStatusLabel1.Text = " Device Tested"; 
    } 
    else 
    { 
     toolStripStatusLabel1.Text = "Try Again or Communication With Device Failure...."; 
    } 
} 

上述代码是读取一个传感器即datarec = serialport_FT(0,1);函数为GUI端提供了一个传感器输出,后面会用红色\绿色描述ovalShapeX(1-6)

问题:datarec = serialport_FT(0, 1);这个函数需要liltime,因此GUI会冻结,直到那个时候如何避免这种情况?

我试过使用后台工作器,但没有得到在哪里把整个过程 也遇到了交叉线程操作错误,当它去到ovalShape并改变它的属性。

我没有收到在后台使用什么功能的一部分,何时何地回到第一线

请帮我使用的BackgroundWorker或使用调用,如果我必须使用线程

+0

在后台线程中调用serialport_FT() - 请参阅http://stackoverflow.com/search?q=c%23+gui+background – Slugart

+0

使用backgroundworker,将'serialport_FT(0,1)'放入'DoWork()'并将'if(datarec){...}'放入'Completed()'事件中。 –

+0

为了避免出现交叉线程异常,请执行以下操作:http:// stackoverflow。com/a/1136406/400303 – Mohammad

回答

5

你可以做这样的事情:

toolStripStatusLabel1.Text = " Device Testing..."; 
positive = false; 
clearsensors_gui(); 
datarec = false; 
cmd = 04; 

BackgroundWorker worker = new BackgroundWorker(); 

worker.DoWork += delegate(object s, DoWorkEventArgs args) 
{ 
    // Will be run on background thread 
    args.Result = serialport_FT(0, 1); 
}; 

worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args) 
{ 
    bool result = (bool)args.Result; 

    if (result) 
    { 
     // Do your UI updates here 
    } 
}; 

worker.RunWorkerAsync(); 

一个改进可能是datarecrec_data结合在args.Result元组。

+0

谢谢......试过这个......我这次没有得到任何错误,但UI消息得到了更新。我把这个块:** if(datatarec){...} **放在** if(result){...} **之下。我究竟做错了什么? – pdthekd

+0

你是否检查serialport_FT是否返回true,结果是否正确? – ekholm

+0

是的结果是真的......所以在此之后,我调用另一个函数,其中有**如果(datarec){...} ** [问题发布] ovalShapesX [1-6]没有更新既不给我例外或错误 – pdthekd

2

在后台工作者中,您使用DoWork事件。

worker.DoWork += new DoWorkEventHandler(yourEventHandler); 

void yourEventHandler(object sender, DoWorkEventArgs e) 
{ 
//your work here 
} 
0

将这个在后台线程,你已经尝试过(或更好,但一Task),但要小心,只能通过Control.Invoke(为的WinForms)或Dispatcher.Invoke(对于WPF)来调用GUI相关的操作。

0

使用一个标签,随着任务的进展实时更新。你可以试试这个代码[使用BackGroundWorker]。查看DoWork你放置业务逻辑的位置[请参阅代码中的BusinessClass用法],然后查看ProgressChanged,后台任务随着任务进度实时向用户界面发出信号,&终于看到RunWorkerCompleted任务完成后处理代码的位置,错误或取消。

using System.ComponentModel; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form3 : Form 
    { 
     private BackgroundWorker _worker; 
     BusinessClass _biz = new BusinessClass(); 
     public Form3() 
     { 
      InitializeComponent(); 
      InitWorker(); 
     } 

     private void InitWorker() 
     { 
      if (_worker != null) 
      { 
       _worker.Dispose(); 
      } 

      _worker = new BackgroundWorker 
      { 
       WorkerReportsProgress = true, 
       WorkerSupportsCancellation = true 
      }; 
      _worker.DoWork += DoWork; 
      _worker.RunWorkerCompleted += RunWorkerCompleted; 
      _worker.ProgressChanged += ProgressChanged; 
      _worker.RunWorkerAsync(); 
     } 


     void DoWork(object sender, DoWorkEventArgs e) 
     { 
      int highestPercentageReached = 0; 
      if (_worker.CancellationPending) 
      { 
       e.Cancel = true; 
      } 
      else 
      { 
       double i = 0.0d; 
       int junk = 0; 
       for (i = 0; i <= 199990000; i++) 
       { 
        int result = _biz.MyFunction(junk); 
        junk++; 

        // Report progress as a percentage of the total task. 
        var percentComplete = (int)(i/199990000 * 100); 
        if (percentComplete > highestPercentageReached) 
        { 
         highestPercentageReached = percentComplete; 
         // note I can pass the business class result also and display the same in the LABEL 
         _worker.ReportProgress(percentComplete, result); 
         _worker.CancelAsync(); 
        } 
       } 

      } 
     } 

     void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      if (e.Cancelled) 
      { 
       // Display some message to the user that task has been 
       // cancelled 
      } 
      else if (e.Error != null) 
      { 
       // Do something with the error 
      } 
     } 

     void ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      label1.Text = string.Format("Result {0}: Percent {1}",e.UserState, e.ProgressPercentage); 
     } 
    } 

    public class BusinessClass 
    { 
     public int MyFunction(int input) 
     { 
      return input+10; 
     } 
    } 
} 
+0

我不明白这一点......你可以多做一点阐述? – pdthekd

+0

你没有得到什么? –

1

当你正在使用的WinForms,这里是一个伟大的MSDN文章,让你开始在应用程序中使用多个线程:Give Your .NET-based Application a Fast and Responsive UI with Multiple Threads

这篇文章是“几天老”,但原则仍然今天绝对有效。

如果您使用的是.NET 4.x版本,则还可以使用Task Parallel Library来更轻松地处理多个线程。

即将推出的.NET 4.5还提供了更加舒适的await和asyc关键字:Asynchronous Programming with Async and Await