2011-11-04 24 views
4

我對混合事件和線程知之甚少。該場景是在PC上運行C#程序,在PLC上運行Twincat。我們需要訪問C#程序中的PLC變量(已經沒有後臺工作線程並且工作正常)。現在我們需要將這些處理移動到一個線程(最好是Background Worker)。這個代碼不起作用(表單中包含一個START按鈕,它將啓動BGworker,一個停止按鈕,它將取消BGWorker,以及一個UPDATE按鈕,它可以將PLC的值更新到文本框中),但現在tcClient_OnNotification沒有被調用!請指出我失蹤的地方,任何幫助將不勝感激。C#Backgroundworker和Twincat,如何觸發工作線程內的通知事件

using System; 
    using System.Collections.Generic; 
    using System.ComponentModel; 
    using System.Data; 
    using System.Drawing; 
    using System.Linq; 
    using System.Text; 
    using System.Windows.Forms; 


    using System.Threading;   // not added by default 
    using System.IO;    // not added by default 
    using TwinCAT.Ads;    // not added by default 

    namespace BGworker 
    { 
     public partial class Form1 : Form 
     { 
      private BackgroundWorker bw = new BackgroundWorker(); 
      private TcAdsClient tcClient; // C# program is the client. 
      private AdsStream dataStream; // Data transfered through System IOStream 
      private BinaryReader binReader; // We are now reading value from PLC 
      private int Hintval;   // Handle for integer value 

      public static bool looping = true; 
      public static string receivedtext = ""; 

      public Form1() 
      { 
       InitializeComponent(); 

       bw.WorkerReportsProgress = true; 
       bw.WorkerSupportsCancellation = true; 
       bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
       bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 
       bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 
      } 

      private void Form1_Load(object sender, EventArgs e) 
      { 

      } 


      private void Startbutton_Click(object sender, EventArgs e) 
      { 
       if (bw.IsBusy != true) 
       { 
        bw.RunWorkerAsync(); 
       } 

      } 




      private void Stopbutton_Click(object sender, EventArgs e) 
      { 
       if (bw.WorkerSupportsCancellation == true) 
       { 
        bw.CancelAsync(); 
       } 
      } 


      public void bw_DoWork(object sender, DoWorkEventArgs e) 
      { 
       BackgroundWorker worker = sender as BackgroundWorker; 
       dataStream = new AdsStream(1 * 2); // Single value will be read 
       binReader = new BinaryReader(dataStream, Encoding.ASCII); 
       tcClient = new TcAdsClient(); 
       tcClient.Connect(801); 
       //Hintval = tcClient.CreateVariableHandle(".GOUTINT"); 
       Hintval = tcClient.AddDeviceNotification(".GOUTINT", dataStream, 0, 2, AdsTransMode.OnChange, 100, 0, null); 
       tcClient.AdsNotification += new AdsNotificationEventHandler(tcClient_OnNotification); 

       while (true) 
       { 
        if ((worker.CancellationPending == true)) 
        { 
         e.Cancel = true; 
         break; 
        } 
        else 
        { 
         System.Threading.Thread.Sleep(100); 
         //worker.ReportProgress((5* 10)); 

        } 
       } 

       tcClient.Dispose(); 
      } 


      public void tcClient_OnNotification(object sender, AdsNotificationEventArgs e) 
      { 
       try 
       { 
        // Setting the position of e.DataStream to the position of the current required value 
        e.DataStream.Position = e.Offset; 

        // Determining which variable has changed 
        if (e.NotificationHandle == Hintval) 
        { 
         receivedtext = binReader.ReadInt16().ToString(); 
        } 
       } 
       catch (Exception ex) 
       { 
        MessageBox.Show(ex.Message); 
       } 
      } 

      private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
      { 
       if ((e.Cancelled == true)) 
       { 
        this.tbProgress.Text = "Canceled!"; 
       } 

       else if (!(e.Error == null)) 
       { 
        this.tbProgress.Text = ("Error: " + e.Error.Message); 
       } 

       else 
       { 
        this.tbProgress.Text = "Done!"; 
       } 
      } 
      private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
      { 
       this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%"); 
      } 

      private void buttonUpdate_Click(object sender, EventArgs e) 
      { 
       this.tbProgress.Text = receivedtext; 
      } 

     } 
    } 

在此先感謝。 Abhilash。

回答

0

我猜想TcAdsClient是他自己被通知一個線程,嘗試調用你的事件的線程,使用標準的消息循環創建它。

問題是,您在ThreadPool線程上創建了它,並且您不會在那裏集合任何消息,因此您的方法從不會被調用。

您的BackgroundWorker看起來完全沒用,因爲無論如何它沒有做任何工作。只要刪除它。

+0

其實BackgroundWorker將完成所有的數據庫工作,我沒有包括在這裏。所以我不能刪除它。 我不明白你的第二點,你能否詳細說一點 – abhilash

7

檢查TcAdsClient.Synchronize

TwinCAT ADS.NET Help說:

如果同步設置爲true,通知被同步到 主線程。這對於Windows Forms項目是必需的。在 控制檯應用程序中,此屬性應設置爲false。

+0

太糟糕了,因爲這絕對*是*答案,因爲我今天發現了 – stijn

5

你一定要檢查是否爲您提供以下工作:

myTcAdsClient.Synchronize = false 

初始化您TcAdsClient實例之後,這樣做的權利。在基於GUI的應用程序中,將Synchronize設置爲true非常重要,這些應用程序嚴重依賴主線程。

在我當前的項目中,我創建了一個圍繞TcAdsClient的包裝類,以便能夠在啓動和停止TwinCat環境的Windows服務中使用它,但包裝設備類將託管AdsClient放在一個單獨的線程中運行()循環)。

對於TwinCat變量方面的更改通知,我的包裝類提供了Windows服務所連接的自己的事件;只要底層TwinCat客戶端的AdsNotificationExEventHandler在設備包裝類中被觸發,就會觸發它。當我在WindowsForms應用程序中測試此設置時,一切正常。但不是在控制檯應用程序中,也不在我的Windows服務中 - AdsNotificationExEventHandler從未被解僱。關鍵是TcAdsClient的線程同步功能 - 默認設置是嘗試將所有通知同步到主線程,這不是我的設置的正確選擇。對你來說,情況似乎也是如此。

+0

我希望我能給你多一個投票! :) –