Как передать логическое значение из Worker_ProgressChanged в Worker_DoWork - PullRequest
0 голосов
/ 02 октября 2018

Я использую фоновый рабочий для чтения значений и передачи значений в Worker_ProgressChanged, для обновления пользовательского интерфейса.

В Worker_DoWork:

while (agi.DvmReadyToRead)   // wait for digipot to be adjusted before reading in worker
{
    Thread.Sleep(20);
    Application.DoEvents();
    //logS.Debug("Waiting for ready to read in worker");
}
Thread.Sleep(40);  // Give digipot chance to make the change
agi.SendSoftwareTriggerOne();
Thread.Sleep(7);    // Duration for above command to execute
A = agi.ReadOne();
Thread.Sleep(1);    
agi.InitOne();
Thread.Sleep(1);    
sAndH3 = A[0];
worker.ReportProgress(0, new System.Tuple<double>(sAndH3));
agi.DvmReadyToRead = true;

В Worker_ProgressChanged:

while (!agi.DvmReadyToRead)
{
    //logS.Debug("waiting for ready to read in progress");
    Thread.Sleep(0);
    Thread.Sleep(0);
    Thread.Sleep(0);
    Thread.Sleep(0);
    Thread.Sleep(0);
    Application.DoEvents();  // Exception thown here
    Thread.Sleep(1);     // wait for DVM reading
}
agi.DvmReadyToRead = false;

// Then goes on to adjust output voltage up or down

Это нормально работает в первый раз, используя

Application.DoEvents();

, однако после первого запуска я получаю переполнение стека в этой точке.После прочтения многих постов здесь DoEvents - не лучший способ сделать то, чего я пытаюсь достичь.Поэтому мне бы хотелось, чтобы это был способ передачи логического значения обратно в DoWork или другой способ, позволяющий работнику иметь возможность читать логическое значение agi.DvmReadyToRead.

Спасибо!

1 Ответ

0 голосов
/ 02 октября 2018

Если я понимаю ваш вопрос, вы описываете очень распространенную схему в разделе «Тестирование и измерение», где у вас есть инструмент, для которого требуется некоторое время после его запуска, прежде чем он получит показание.Но вы хотите знать, когда происходит чтение, чтобы вы могли предпринять какие-то действия (например, обновить ProgressBar или TextBox), и вы хотите иметь возможность отменить рабочий цикл.

Когда мне нужно сделать это самостоятельно,Мне нравится использовать System.Threading.Tasks для упрощения вещей.Я опубликую полный образец здесь в надежде, что вы сможете найти что-то полезное для решения вашей проблемы.

Чтобы было ясно, я пытаюсь ответить на ваш вопрос о "способе передачи логического значения обратно в DoWork ...", сказав, что один из способов сделать это - запустить событие из Worker_DoWork, которое может содержатьBoolean (как вы просили) или double (в моем примере) или любая другая информация, которую вы выбираете.

Удачи!

using System;
using System.ComponentModel;    
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace StackOverflow02
{
    public partial class DVMLoopRunner : Form
    {
        public DVMLoopRunner()
        {
            InitializeComponent();
            DVMReadingAvailable += Form1_DVMReadingAvailable;
            ContinueOrCancel += Form1_ContinueOrCancel;
        }

        // See if User has turned off the Run button then cancel worker
        private void Form1_ContinueOrCancel(Object sender, CancelEventArgs e)
        {
            e.Cancel = !checkBoxRunMeterLoop.Checked;
        }

        // The DVM, after being triggered + some delay, has come up with a new reading.
        private void Form1_DVMReadingAvailable(Object sender, DVMReadingAvailableEventArgs e)
        {
            // To update GUI from worker thread requires Invoke to prevent Cross-Thread Exception
            Invoke((MethodInvoker)delegate
            {
                textBox1.Text = e.Reading.ToString("F4");
            });
        }

        // Make our events so that we can be notified of things that occur
        public event CancelEventHandler ContinueOrCancel;                   
        public event DVMReadingAvailableEventHandler DVMReadingAvailable;

        // This is how we will provide info to the GUI about the new reading
        public delegate void DVMReadingAvailableEventHandler(Object sender, DVMReadingAvailableEventArgs e);
        public class DVMReadingAvailableEventArgs : EventArgs
        {
            public readonly double Reading;
            public DVMReadingAvailableEventArgs(double reading)
            {
                Reading = reading;
            }
        }

        // When the User checks the box, Run the worker loop
        private void checkBoxRunMeterLoop_CheckedChanged(Object sender, EventArgs e)
        {
            if(checkBoxRunMeterLoop.Checked)
            {
                Task.Run(() => ReadDVMWorker());
            }
        }

        // Worker Loop
        private void ReadDVMWorker()
        {
            while(true)
            {
                CancelEventArgs e = new CancelEventArgs();
                ContinueOrCancel?.Invoke(this, e);
                if (e.Cancel) return;               // If User has turned off the Run button then stop worker
                ReadDVM();                          // This worker thread will block on this. So trigger, wait, etc.
            }
        }

        // DVM Takes some period of time after trigger
        void ReadDVM()
        {
            Thread.Sleep(1000);
            double newSimulatedReading = 4.5 + Random.NextDouble();
            DVMReadingAvailable?.Invoke(this, new DVMReadingAvailableEventArgs(newSimulatedReading));
        }
        Random Random = new Random();   // Generate random readings for simulation
    }
}

enter image description here

...