2013-03-02 126 views
0

我有這樣的功能:如何在使用BakcgroundWorker時避免invalidOperationException?

private void cpuView() 
     { 
      if (pauseContinueDoWork == true) 
      { 
      } 
      else 
      { 
       Computer myComputer = new Computer(); 
       myComputer = new Computer(settings) { CPUEnabled = true }; 

       myComputer.Open(); 
       Trace.WriteLine(""); 
       foreach (var hardwareItem in myComputer.Hardware) 
       { 
        if (hardwareItem.HardwareType == HardwareType.CPU) 
        { 
         hardwareItem.Update(); 
         foreach (IHardware subHardware in hardwareItem.SubHardware) 
          subHardware.Update(); 

         foreach (var sensor in hardwareItem.Sensors) 
         { 
          settings.SetValue("sensor", sensor.Value.ToString()); 
          if (sensor.SensorType == SensorType.Temperature) 
          { 
           sensor.Hardware.Update(); 
           settings.GetValue("sensor", sensor.Value.ToString()); 
           label17.Text = sensor.Value.ToString() + "c";//String.Format("{0} Temperature = {1}c", sensor.Name, sensor.Value.HasValue ? sensor.Value.Value.ToString() : "no value"); 
           tempCpuValue = sensor.Value; 
           if (sensor.Value > 60) 
           { 
            Logger.Write("The Current CPU Temperature Is ===> " + sensor.Value); 
            button1.Enabled = true; 
           } 
           int t = label17.Text.Length; 
           if (t >= 4) 
           { 
            label17.Location = new Point(50, 50); // not working to check everything about the locations \\ 

           } 
           else 
           { 
            label17.Location = new Point(50, 50); 
           } 

           break; 
          } 
         } 
        } 
       } 
      } 
     } 

我打電話在後臺工作這個功能(DoWork的事件):

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
     { 
      BackgroundWorker worker = sender as BackgroundWorker; 
      while (true) 
      { 

       if ((worker.CancellationPending == true)) 
       { 
        e.Cancel = true; 
        break; 
       } 
       else 
       { 
        if (tempCpuValue >= (float?)nud1.Value || tempGpuValue >= (float?)nud1.Value) 
        { 
         soundPlay = true; 
         blinking_label(); 
         NudgeMe(); 
        } 
        else 
        { 
         soundPlay = false; 
         stop_alarm = true; 

        } 
        cpuView(); 
        gpuView(); 
        Thread.Sleep(1000); 
       } 
      } 
     } 

在這種情況下,唯一的例外是在cpuview功能上這條線:

label17.Text = sensor.Value.ToString() + "c"; 

錯誤消息是:跨線程操作無效:控制'label17'從其創建的線程以外的線程訪問。

異常消息:

System.InvalidOperationException was unhandled by user code 
    HResult=-2146233079 
    Message=Cross-thread operation not valid: Control 'label17' accessed from a thread other than the thread it was created on. 
    Source=System.Windows.Forms 
    StackTrace: 
     at System.Windows.Forms.Control.get_Handle() 
     at System.Windows.Forms.Control.set_WindowText(String value) 
     at System.Windows.Forms.Control.set_Text(String value) 
     at System.Windows.Forms.Label.set_Text(String value) 
     at HardwareMonitoring.Form1.cpuView() in d:\C-Sharp\HardwareMonitoring\HardwareMonitoring\Hardwaremonitoring\Form1.cs:line 378 
     at HardwareMonitoring.Form1.backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in d:\C-Sharp\HardwareMonitoring\HardwareMonitoring\Hardwaremonitoring\Form1.cs:line 655 
     at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e) 
     at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument) 
    InnerException: 

如何解決/解決這個問題?

回答

1

您正在嘗試從後臺線程訪問UI - 因此「跨線程操作無效:」消息。

您需要從後臺工作人員向UI線程發送事件並使用Invoke來更新UI。在這裏,我已經實現了它作爲一個擴展方法,因此可以從任意控制被稱爲:

public static void InvokeIfRequired(this Control control, Action action) 
{ 
    if (control.InvokeRequired) 
    { 
     control.Invoke(action); 
    } 
    else 
    { 
     action(); 
    } 
} 

哪裏control是要更新和action()是要調用的方法的UI元素。然後你可以這樣調用:

this.label17.InvokeIfRequired(() => this.label17.UpdateLabel(sensor.Value.ToString() + "c")); 

private static void UpdateLabel(this Label label, string newValue) 
{ 
    label.Text = newValue; 
} 
+0

ChrisF即時得到的this.label17.ImvokeIfRequired行錯誤:錯誤「System.Windows.Forms.Label」不包含一個定義爲「InvokeIfRequired」並且沒有找到接受'System.Windows.Forms.Label'類型的第一個參數的擴展方法'InvokeIfRequired'(您是否缺少using指令或程序集引用?)UpdateLabel的同一行上出現同樣的錯誤 – user2065612 2013-03-03 00:46:02

+0

@ user2065612 - InvokeIfRequired是一個擴展方法(我看到的答案並不清楚)。 – ChrisF 2013-03-03 12:10:29

1

你正在從後臺線程進入UI線程的調用。您需要使用控制器上的BeginInvoke以使用委託進行更新或使用ReportProgress方法。

例如:

public delegate void InvokeDelegate(); 

private void DoWork() 
{ 
    label17.BeginInvoke(new InvokeDelegate(InvokeMethod)); 
} 

public void InvokeMethod() 
{ 
    label17.Text = "I execute on the UI thread!"; 
} 
相關問題