2011-11-04 90 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

我希望我能给你多一个投票! :) –