C # Backgroundworker и Twincat, Как запустить событие уведомления внутри рабочего потока - PullRequest
4 голосов
/ 04 ноября 2011

Я мало знал о смешивании событий и потоков.Сценарий заключается в том, что на ПК запущена программа на C #, а на ПЛК - Twincat.Нам нужно получить доступ к переменным ПЛК внутри программы на C # (уже выполнено без фонового рабочего потока и его нормально работающий.) Теперь нам нужно переместить эту обработку в поток (предпочтительно Background Worker).Вот код, который не работает. (Форма содержит кнопку START, которая запустит BGworker, кнопку STOP, которая отменит BGWorker, и кнопку UPDATE, которая обновит значения из PLC в текстовое поле.), Но теперь tcClient_OnNotificationне звонят!Пожалуйста, укажите, где я пропускаю, любая помощь будет наиболее ценной.

    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.

Ответы [ 3 ]

7 голосов
/ 19 апреля 2012

Проверка TcAdsClient.Synchronize

Справка TwinCAT ADS.NET говорит:

Если для параметра Синхронизация задано значение true, уведомления синхронизируются в главном потоке,Это необходимо для проектов Windows Forms.В консольном приложении это свойство должно быть установлено в false.

5 голосов
/ 04 марта 2014

Вы должны обязательно проверить, работает ли для вас следующее:

myTcAdsClient.Synchronize = false 

Сделайте это сразу после инициализации вашего экземпляра TcAdsClient.Установка Synchronize в true имеет смысл в приложениях на основе графического интерфейса, которые сильно зависят от основного потока.

В моем текущем проекте я создал класс-оболочку для TcAdsClient, чтобы иметь возможность использовать его в службе Windows, которая запускает и останавливает среду TwinCat, но класс устройства-оболочки размещает AdsClient в отдельном потоке (вбесконечный цикл Run ().

Для уведомления об изменениях в терминах переменных TwinCat мой класс-обертка предлагает собственное событие, к которому подключена служба Windows;он срабатывает всякий раз, когда AdsNotificationExEventHandler базового клиента TwinCat запускается внутри класса оболочки устройства.Когда я тестировал эту настройку в приложении WindowsForms, все работало нормально.Но не в консольном приложении и не в моей службе Windows - AdsNotificationExEventHandler никогда не срабатывал.Ключом является функция синхронизации потоков в TcAdsClient - настройка по умолчанию - это попытка синхронизировать все уведомления в главном потоке, что не было правильным выбором для моей настройки.Похоже, то же самое относится и к вам.

0 голосов
/ 04 ноября 2011

Я предполагаю, что TcAdsClient сам уведомляется в потоке, попытайтесь вызвать ваше событие в Потоке, который его создал, используя стандартный цикл сообщений.

Проблема в том, что вы создали его впоток ThreadPool и вы не объединяете там никакие сообщения, поэтому ваш метод никогда не вызывается.

Ваш BackgroundWorker кажется совершенно бесполезным, так как в любом случае он не выполняет никакой работы.Просто удали его.

...