I'm trying to have serial data sent out continuously while a check button is being pressed in Visual Studio. So far, this is what I've come up with:
private void checkBox1_CheckedChanged_1(object sender, EventArgs e)
{
while (checkBox1.Checked)
{
serialPort1.Write("D");
Task.Delay(100);
if (checkBox1.Checked != true)
{
break;
}
} `
For some reason, whenever I launch the program and check the box, the program
freezes. I can't exit the program or minimize it or anything. It just stops in its tracks.
The user interface in Windows is based on messages. Your while loop runs in the thread where those messages would be handled. While your code runs, no messages are handled. The user interface cannot be redrawn and cannot react to user input.
Better approach: Use a Timer component. The Tick event of the Timer will be executed every n milliseconds according to the Interval property of the Timer. In the Tick event, you can check the Checkbox state and then do something or not depending on whether the checkbox is checked.
This is a good approach if "do something" is a very short activity. For longer activities, you nee a bit more complex setup that is beyond the scope of a SO question unless you provide more details.
You're blocking the UI thread because your event is being handled synchronously. Refer to this answer for some tips on async/await programming: How do I update the GUI from another thread?
Related
I have a FileSystemWatcher that is waiting for files to appear in a folder, which then triggers an insert to an ObservableCollection. When the form is open on the screen the update happens successfully. But when the form is minimized I get a cross-thread exception? I know I can just check for context, but I want to know why this behaviour is happening so I can ensure it doesn't come up again in other places.
I've tried this with a new blank winform app, and it errors 100% of the time whether it is minimised or not, so I'm unsure what I'm doing wrong or how to diagnose the issue. The main app is thousands of lines long, with many custom libraries so I can't post all of it here.
Called by the watcher
private void CheckForFiles(object source, FileSystemEventArgs e)
{
WaitingFiles.Add(e.FullPath);
}
Which triggers this
private async void WaitingFiles_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
CurrentProcessStatusLabel.Text = "Checking download for despatch file";
}
When I minimize the window I run the following code;
Hide();
SysTrayIcon.Visible = true;
Unless a SynchronizingObject is set, events are raised on a background thread, and background threads are not allowed to update the UI. I'm not sure why it works unless the application is minimized, but a good start is to ensure you are using correct synchronization to avoid issues like this.
If you want to update the UI you should either set the SynchronizingObject to one of the controls in your UI, or manually schedule any UI updates to the UI thread.
Why will this click event not display the first toast message?
I created a break point and it hits the line to display "Waiting on User Input..." but never displays. I only get a 5 second wait and then an Approved or Declined toast notification.
private void Button_Credit_Click(object sender, RoutedEventArgs e)
{
myToast.Show("Waiting on User Input...");
System.Threading.Thread.Sleep(5000);
if (pc.BuildTransaction())
myToast.Show("Approved");
else
myToast.Show("Declined");
}
You shouldn't use Thread.Sleep, but instead utilize Task.Delay, so you're not blocking the current thread during your specified delay.
If you block your current thread, which in this situation is much likely your UI thread, how do you expect it to be able to dispatch your toast notification?
I want to prevent a button click from queuing. In testing I have a Form, a Button and in the Code-Behind I have the event handler:
private void button1_Click(object sender, EventArgs e)
{
if (_codeRunning)
return;
_codeRunning = true;
//Application.DoEvents();
//button1.Enabled = false;
_click ++;
Debug.WriteLine("Click Number: " + _click);
Task.Delay(5000).Wait();
//button1.Enabled = true;
_codeRunning = false;
}
When I run debug and click the button twice or three or four times rapidly, Debug Output shows each click about five seconds after the last one. What I would like it to show is a single Click and drop the rest until first Event is complete.
I have also tried to disable the button, as well as temporarily remove the Handler from the Button_click event. It is all the same results.
There are various amounts of trouble you'll get into when you hang-up the UI thread like this. This is certainly one of them, nothing pleasant happens when the user wildly bangs on the button to try to get something noticeable to happen. And sure, those clicks won't get lost, they stay stored in the message queue. To activate your Click event handler again when your event handler stops running.
Pretty important to learn how to use the BackgroundWorker or Task classes to avoid this kind of trouble. Just setting the button's Enabled property is then enough to solve this problem.
Purging the mouse clicks from the message queue is technically possible. But ugly to do, it requires pinvoke. I'll hesitantly post the alternative, don't assume that this is in general a good strategy. You'll need to read this post to have some insight into why DoEvents() is a dangerous method.
private void button1_Click(object sender, EventArgs e) {
button1.Enabled = false;
button1.Update();
'' long running code
''...
Application.DoEvents();
if (!button1.IsDisposed) button1.Enabled = true;
}
The Update() call ensures that the user gets the feedback he needs to know that banging the button repeatedly isn't going to do anything useful. The DoEvents() call will dispatch all the queued-up mouse clicks, nothing happens with them since the button is still disabled. The IsDisposed test is essential to solve the problem with DoEvents(), it ensures your program won't crash when the user clicked the window's Close button while the code was running.
Use the HourGlass class in this post to provide more feedback.
I had a button that on click event was going to run a method. Same issue happent and when the user clicked multiple times the method was triggered multiple times. So I made a boolean and changed it value when the method started.
private bool IsTaskRunning = false;
private void MyMethod()
{
if ( IsTaskRunning==false )
{
IsTaskRunning=true;
// My heavy duty code that takes a long time
IsTaskRunning=false; // When method is finished
}
}
So now the method runs only if it's done the last time.
I have this code:
private void timer1_Tick(object sender, EventArgs e)
{
MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
}
the timer is enabled, with interval = 100.
This result in an infinite number of message boxes to appear over each other, when I was expecting them to simply BLOCK the next event until the current messagebox is closed.
In more complicated applications this could lead to unpreditable results, and its as if more than 1 thread have access to the same function, but actually it is the same thread.
Why is this happening ?
The message box is a modal dialog which pumps the message queue. And so that allows for the timer tick messages to fire, since they are posted to the GUI thread's message queue.
This is always the case for a modal dialog that is shown in the GUI thread. Since each thread has only one message queue, the modal dialog's message pump will pull of the timer tick messages.
It is happening exactly how it should. The tick event is powered by the message loop (unless you're using a threaded variant) and will be called repeatedly unless you block the message loop in some way (think Thread.Sleep or non message based code execution).
The message box doesn't block, it's just another window and as long as the message pump of the application is functioning so will the window, and so as each tick happens new dialogs can be created and stacked up.
A quick solution to this is something like:
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
timer1.Start();
}
This would stop the timer, show a dialog and allow the timer to recover after the dialog is closed. This means you'd only get the one dialog and not a perpetual stack of them.
I am working on a C# winform application which continuously navigates some links in a webbrowser control and process the data of that webpage. I need to provide two buttons on the form for Pause and Resume.
On click of button the whole application should get pause processing and after that on click of Resume button it should start again.
So to pause the application, on click of Pause button I made thread to sleep for infinite time by following code.
private void Pause_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
}
But this piece of code unable the user to click on Resume Button on form to resume the application. Also I am not getting a perfect piece of code to resume the application on click of Resume Button.
Can Anyone get me the correct solution for this issue ?
Thread.Sleep method yields execution of code to process scheduler and doesn't get it back until specified time passes. Therefore you can't make sleeping thread wake itself up. You can't even make a working thread wake another sleeping thread (to my knowledge).
You need to accomplish your goal differently.
Separate data processing code to separate, worker, method
Run worker method in separate thread
Share a state variable between UI and worker thread. This variable should pass signals on whether execution should be paused.
From UI thread, set pause signals in shared variable as needed
In processing loop, write handler code for stopping processing
I'll post some pseudo code below on how you should do this:
private bool _Paused = false;
private void OnPauseClick()
{
_Paused = true;
}
private void OnResumeClick()
{
_Paused = false;
}
private void OnRunClick()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(WorkerMethod));
}
private void WorkerMethod(object state)
{
...
while (needToDoMoreWork)
{
// do some work here
...
// if pause requested, wait to unpause
while (_Paused)
{
// Sleep for a short time and check again if paused
Thread.Sleep(100);
}
}
}
You'll need to fill in the blanks according to your business needs.
If you put your UI thread to indefinite sleep, you're going to kill your UI indefinitely. Don't do that.
Your application has some mechanism to know it's time to do its navigation and processing, probably a timer of some sort. If it's a timer, just stop it when you pause the application, and start it again when you resume. If it's some other mechanism, you need to stop it,too, but it's hard to tell you how without knowing what that mechanism is.