Reputation: 83
I have a small program that's supposed to sample some value from a device connected via USB. I want to sample the device every 0.5 seconds - so I created a loop that repeats itself every 500miliseconds and works pretty well:
while(_bool)
{
Sample_USB_Device();
Present_Data_To_Screen();
}
My question is this:
How can I control the _bool
variable? When I run the code the GUI freezes and I don't have any access to it. I tried to used Threads, but I can't send the data back from the thread to the GUI (or I don't know how).
Upvotes: 2
Views: 484
Reputation: 1994
Using a Timer with C# 5.0 & TPL will allow you to invoke an async event handler which at the defined interval, which will poll the device and automagically marshall the result back onto the UI Thread.
public partial class Form1 : Form
{
private readonly Timer _sampleTimer;
public Form1()
{
InitializeComponent();
_sampleTimer = new Timer
{
Interval = 500 // 0.5 Seconds
};
_sampleTimer.Tick += SampleUsb;
}
private async void SampleUsb(object sender, EventArgs e)
{
// Since we asynchronously wait, the UI thread is not blocked by "the work".
var result = await SampleUsbDeviceAsync();
// Since we resume on the UI context, we can directly access UI elements.
resultTextField.Text = result;
}
private async Task<string> SampleUsbDeviceAsync()
{
await Task.Delay(1000); // Do actual work sampling usb async (not blocking ui)
return DateTime.Now.Ticks.ToString(); // Sample Result
}
private void startButton_Click(object sender, EventArgs e)
{
_sampleTimer.Start();
}
private void stopButton_Click(object sender, EventArgs e)
{
_sampleTimer.Stop();
}
Upvotes: 0
Reputation: 172468
Use a BackgroundWorker to execute your loop in the background. This will ensure that your UI stays responsive:
BackgroundWorker bw;
public void StartBackgroundLoop() {
bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.WorkerReportsProgress = true;
bw.DoWork += (sender, e) => {
// this will happen in a background thread
while (!bw.CancellationPending) {
data = Sample_USB_Device();
bw.ReportProgress(0, data);
}
}
// this event is triggered *in the UI thread* by bw.ReportProgress
bw.ProgressChanged += (sender, e) => {
Data data = (Data)e.UserState; // this is the object passed to ReportProgress
Present_Data_To_Screen(data);
}
bw.RunWorkerAsync(); // starts the background worker
}
public void StartBackgroundLoop() {
bw.CancelAsync(); // sets bw.CancellationPending to true
}
Upvotes: 0
Reputation: 839114
You can use a Timer to run your code at a specified interval, instead of using a loop. The timer can be enabled or disabled.
Upvotes: 7
Reputation: 4098
Here, use a backgrounder.
backgroundWorker1.RunWorkerAsync(); // Start the backgroundworker.
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
// Do you stuff here.
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
// Report the changes.
// NOTE: backgroundWorker1.WorkerReportsProgress = true; has to be true.
}
private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
// Do something when we are done.
}
EDIT: This only stops your freezing problem.
Upvotes: 0
Reputation: 371
Upvotes: 0
Reputation: 21044
Use threading:
public class ThreadExample {
private bool _running;
public void start() {
Thread t = new Thread(doStuff);
_running = true;
t.Start();
}
public void stop() {
_running = false;
}
public void doStuff() {
while(_running){
Sample_USB_Device();
Present_Data_To_Screen();
Thread.Sleep(500);
}
}
}
Upvotes: 0