"Simple" C# Time Thread Appears to be Freezing - c#

I've been staring at this thread for some time and I believe my mind has shut down on it. Thinking that the best thing to do, in order to update the time in a UI TextBox, would be to create what I thought would be a simple thread to get the time and post it back to the UI control. After having fought with it for a while, I'm getting frustrated and thinking that I might just add the time in some other way. In the intrepid spirit of the adventurer, I'm giving it another go.
I've got a similar thread operating elsewhere in the app that takes a list and populates a DataGridView in a TabControl. I'd have thought that the process would be roughly the same, but I'm missing a key part. The entirety of the thread is below:
private void displayTime()
{
while (true)
{
String time;
String date;
time = DateTime.Now.TimeOfDay.ToString();
int len = time.IndexOf('.');
time = time.Substring(0, len);
date = DateTime.Now.Date.ToString();
len = date.IndexOf(' ');
date = date.Substring(0, len);
updateClock(time, date);
}
}
private void updateClock(String time, String date)
{
if (InvokeRequired)
{
BeginInvoke(new timeDel(updateClock), new object[] {time, date});
return;
}
ctrlTimeTxt.Text = time + "\n" + date;
}
The above thread has been started in various places(in an attempt to debug), but is currently in the Form's Shown event handler. The Form begins to appear, but then everything seems to hang. When I place a breakpoint in the thread, I can step ad infinitum, but the UI never seems to get control back. What am I missing? I'll be happy to expand upon any neglected details.
Edit: A clarification: This thread is being started in a function that is handling the Shown event. The description of the Shown event is given as: Occurs whenever the Form is first shown. I think that might eliminate the theory that the UI thread is Invoking too quickly.

The problem is that your while loop here is generating so many events that the event queue gets flooded:
while (true)
{
// ...
updateClock(time, date);
}
Instead of doing this in a thread you can use a Timer to generate events at a regular interval and do one step of your method for each event. This will also mean that you don't have to use Invoke as the timer generates events on the main thread.
There are also two other errors in your code:
Occasionally TimeOfDay.ToString() could output a time that hits exactly at a second change, in which case the result of ToString() will not be "12:23:34.00000" but just "12:23:34" which will cause your method to throw an exception.
You are calling DateTime.Now twice, but the value could have changed in between the two calls. Normally this won't matter but as it passes midnight it could show '23:59:99.999' but the day shows as the next day. It's probably not a significant error in this application but you ought to get into the habit of only calling DateTime.Now once when you want consistent values for the date and time.
To fix these errors and to simplify your code:
Add a timer to your form.
Set the timer's Enabled property to true in the designer.
Add this event handler to the Tick event:
private void timer_Tick(object sender, EventArgs e)
{
DateTime now = DateTime.Now;
textBox1.Text = now.ToString("HH:mm:ss\nyyyy-MM-dd");
}
You may wish to adjust the format string depending on your needs.

It doesn't surprise me that this isn't going well -- you're stuffing invokes in the UI thread message queue (with your BeginInvoke()) as fast as you can generate them. You may want to put a break (i.e. with System.Threading.Thread.Sleep()) in your displayTime() thread to give the UI thread time to do some work.

How do you call displayTime?
If your Form.Show() method is like this
Show()
{
displayTime();
}
Then as Mark answered you are blocking your main UI thread infinitely.
I would start a new thread
Show()
{
Action displayTimeAction = displayTime;
displayTimeAction.BegingInvoke(null, null);
}

Related

Possible causes for thread/timer delay?

In relation to a previous question of mine ([question] : Which thread will timer method run in? ), I've added a Timer to my Windows Forms app to run every 100ms to show how long the program session has been running. I've defined it as follows (these are only the snippets relevant to the timer):
private System.Timers.Timer timerPureTime = new System.Timers.Timer(100);
timerPureTime.Elapsed += new System.Timers.ElapsedEventHandler(updateTimeElapsed);
this.timerPureTime.SynchronizingObject = currentForm; //where currentForm is my main Form
public void updateTimeElapsed(object sender, ElapsedEventArgs e)
{
if (currentForm.lblTimeElapsed.InvokeRequired) //lblTimeElapsed is your standard Windows Form label
{
currentForm.lblTimeElapsed.Invoke((MethodInvoker)delegate //also, trying to make make GUI invoking thread-safe here
{
TimeSpan t = TimeSpan.FromSeconds(purelyTime);
string showTime = string.Format("{0:D2} min {1:D2} sec",
t.Minutes,
t.Seconds);
currentForm.lblTimeElapsed.Text = showTime;
});
}
else
{
TimeSpan t = TimeSpan.FromSeconds(purelyTime);
string showTime = string.Format("{0:D2} min {1:D2} sec",
t.Minutes,
t.Seconds);
currentForm.lblTimeElapsed.Text = showTime;
}
purelyTime += 0.1;
}
As I understand it the Timer should be running in a thread of its own (taken from the Threadpool) however it still experiences some delay every now and then, throwing the timer off-course. Other threads within the application run pretty regularly (every 250ms) and computation-intensive, but shouldn't these be independent of Timer threads?
What could be the possible causes for timer lag in such cases?
Windows cannot guarantee a precisely regular callback for a timer, so you will definitely see that kind of variance.
You need to take a different approach:
Initialise a Stopwatch field in your class.
Call Stopwatch.Restart() when you want to reset the timing.
Inside updateTimeElapsed() use Stopwatch.Elapsed instead of purelyTime.
Note that your code is completely ignoring the amount of time spent in the timer handler function itself. Inside the handler, you are using Invoke to send a message to the UI and waiting for it to return. That can take an arbitrary amount of time, particularly if the UI is busy.

Background timer to update UI?

I got a little problem with my application.
I would like to update something on my UI every 10 seconds. I first used a DispatcherTimer for this but it will block my UI for a short time because the update method needs to load something from the web and this operation needs some time.
Now I thought about some kind of background worker and I found BackgroundTasks.
The problem with Background tasks is, as far as I understood it correctly, that they are supposed to serve as updaters even if the app is suspended. I don't need that.
I only would like to update if my app is running not if it is suspended.
Is there a good way to solve this?
Any suggestions what to use for this?
Thanks in advance!
You need two things for it:
Timer
You can update the UI in System.Timers.Timer with the 10 seconds interval.
Dispatcher
You need to use Dispatcher.Invoke to change the UI without holding the main UI thread. Instead the method Process should be called on a separate thread (Timer method), other than main UI thread, and use Dispatcher in it to alert main UI thread for the change.
Process() // method to be called after regular interval in Timer
{
// lengthy process, i.e. data fetching and processing etc.
// here comes the UI update part
Dispatcher.Invoke((Action)delegate() { /* update UI */ });
}
You need to create a thread that runs the part of your code that gets and processes the information from the website. This way, your form will not hesitate because it will be on a different thread than the processing part.
This Article on code-project should get you started.
Also, you could start a timer, which has a elapsed event, that occurs every time the timer passes a certain time cycle.
http://www.dotnetperls.com/timer
The other answers are missing proper cleanup: When the timer fires in the exact moment that the window was closed, I would get an uncaught TaskCanceledException when trying to run Dispatcher.Invoke. I didn't find help for this problem in other questions. I was able to solve it by unregistering the timer callback when closing the window.
public partial class MainWindow : Window
{
Timer clockTimer = null;
public MainWindow()
{
clockTimer = new Timer(1.0); // 1 ms update to test for TaskCanceledException
clockTimer.Elapsed += Timer_Elapsed;
clockTimer.AutoReset = true;
clockTimer.Start();
Closed += (object sender, EventArgs e) => { clockTimer.Elapsed -= Timer_Elapsed; };
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e) {
var now = DateTime.Now;
Dispatcher.Invoke((Action)delegate () {
UpdateTime(now);
});
}
}
Obviously this is not a good idea if the window was re-shown. I tried adding a dtor, but it would never get called, probably due to cyclic dependencies.
Disclaimer: I don't know C#, so this might not be the best or proper way of doing things.

Multiple Timers WPF application, The calling thread must be STA Error

My WPF application involves several timers. Everything works with DispatcherTimers but the delays are huge and freezes occur often (for example 3 sec freeze then the remaining 3 sec get added at once).
My problem is i am not sure how exactly i have to redesign my application to get around this problem. Never worked with threads before and its my first real WPF application as well.
I get the following error:
The calling thread must be STA, because many UI components require this.
I got this error by replacing my Dispatcher timer by a Timer from the namespace System.Timers
Old code with dispatcher timer:
timerW = new DispatcherTimer();
timerW.Tick += new EventHandler(timerW_Tick);
timerW.Interval = new TimeSpan(0, 0, 5000);
timerW.Start();
New code with Timer:
timerW = new Timer();
timerW.Elapsed += new ElapsedEventHandler(timerW_Tick);
timerW.Interval = 5000;
timerW.Start();
A query gets executed every 5 seconds to retreieve a date value. When certain conditions are met buttons get dynamically created. For example if the date remains the same for 3 min a button gets created.
Dynamic created button contains:
Date from the database
A timer that starts running when the buttons gets created. This timer only stops when a new button gets created, this records the downtime.
A reason for the downtime
The buttons get saved in a ObservableCollection and use Dependency Properties so they get notified when something changes. It is a custom button with several textblocks to display the information.
The button part is where all the interaction is at in my program, the rest of the interface just displays information fro the database. The buttons get placed in a custom made slider like control with left and right navigation buttons.
So in short my program has 3 different dispatcher timers.
One to display the current time (hh:mm:ss format)
One to execute a sql query and retrieve a date value every 5 sec
One to update the downtime timer every second inside a dynamically custom styled WPF button. I use a stopwatch to record the downtime in between.
So it seems i need to work with treads and/or backgroundworker?
Not sure how i actually begin with this since i am pretty clue less for some time now. Some example code would be most welcome.
Tldr:
I use timers for the following reasons:
Display the current time
Record downtime (real time, so i actually see it counting by the second)
A SQL query that gets executed every 5 seconds.
EDIT:
public void InitializeDispatcherTimerW()
{
TimerCallback callback = MyTimerCallBack;
timerWegingen = new Timer(callback, null, 0, 5000);
timerWegingen.Change(0, 5000);
}
private void MyTimerCallBack(object state)
{
DisplayWegingInfo();
CaculateTimeBetweenWegingen();
}
Best regards,
Jackz.
System.Timers.Timer seems to require an STA thread. An STA thread was a requirement for Windows Forms, but WPF apparently doesn't need it.
Does System.Threading.Timer meet your need?
Here is an example:
// firstTickInterval and interval are TimeSpans
TimerCallback callback = MyTimerCallback;
Timer timer = new Timer(callback, null, firstTickInterval, interval);
// timer is now running
// To stop the timer, do timer.Change(-1, -1);
The callback function would look like this:
void MyTimerCallback(object state)
{
// This is not guaranteed to execute on the UI thread.
// In this example, state will be null, since we passed null in the Timer constructor.
}
When timers callback code interact with UI elements You need to use:
UIElement.Dispatcher.BeginInvoke(...);
More info: http://msdn.microsoft.com/en-us/magazine/cc163328.aspx

Issue with timer updating Form

I have a recursive function and would like to update the form with the time, number of attempts and what the current attempt for the recursive function. Every second, the form should update. The current methodinvoker doesn't work. The compiler will highlight the line but not continue and it will pop back out.
I already tried placing the function on a separate thread but, it preforms poorly, so I would prefer to keep the function on the main thread.
Any ideas?
void bruteForce_DoWork()
{
doBruteForceEID("", 0, wordlen, temp);
}
void _myTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (InvokeRequired)
{
runTimeSec++;
this.Invoke(new MethodInvoker(delegate() { this.toolStrip.Text = "Running... " + runTimeSec + "s"; }));
Invoke(new MethodInvoker(delegate() { lblAttackA.Text = Convert.ToString(attackCount); }));
Invoke(new MethodInvoker(delegate { lblCurAttempt.Text = brute; }));
}
else
{
runTimeSec++;
toolStrip.Text = "Running... " + runTimeSec + "s";
lblAttackA.Text = Convert.ToString(attackCount);
lblCurAttempt.Text = brute;
}
}
EDIT: Let me explain the program alitte more... Once the user has inputted their password that they would like to check, the following happens after they hit Calculate.
- Runs a dummy recursive algorithm to see how many cycles their machine can do within 5 seconds, then I average them to give a better idea of how many cycles they can do per sec.
back = new Thread(new ThreadStart(testLoop_DoWork)); // Calls the dummy algorithm
back.Start();
if (rbtnTest.Checked)
{
txtEID.Text = txtUID.Text;
lblRunCycle.Text = "Calculating...";
testTimer.Enabled = true; // Starts the Timer
}
Once the 5 second timer is up, I check the length, cycles per second, what characters (upper,lower,numbers,symbols), give how long it will take, add the respective char arrays for to create the brute force char array, then I Join() the thread and disable the timer.
I would get roughy 7million cycles per second avg...(remember this number). Also, I am NOT updating to the GUI during this time.. Just running the created thread.
Then if the user wants to run the attack, it does:
attackBack = new Thread(new ThreadStart(bruteForce_DoWork));
attackBack.Start();
_myTimer.Enabled = true;
Once I start running it on the new thread, it is displaying only about 30,000 cycles per second?? and my timer is only updating every second. What is going on?
Edit: I also just commented out the timer so nothing is updating to the GUI... and the same results occur when the brute force is found (for example the word 'test' should be instant... but it takes 10 seconds to find it...
Yes, this cannot work. The Timer.Elapsed event runs on a threadpool thread. Which means for one that InvokeRequired is always true and doesn't need to be checked. What can't work is the Invoke() call. It requires the UI thread to be idle so it can executed the invoked code.
Your UI thread isn't idle, it is executing the expensive code. This is called deadlock.
You have to do this the other way around, have a worker thread execute the expensive code instead of the UI thread. Which keeps the UI thread responsive, both to update the labels, keep the UI painted and respond to user input. You said you didn't like doing it this way, it is unclear why you are having a problem with it. A classic mistake is updating the UI too often, flooding it with invoke requests so it doesn't get around to its regular duties anymore. A timed update is indeed the solution. Never update more than 25 times per second, the human eye can't tell the difference if you do it more often than that.

Force GUI update from UI Thread

In WinForms, how do I force an immediate UI update from UI thread?
What I'm doing is roughly:
label.Text = "Please Wait..."
try
{
SomewhatLongRunningOperation();
}
catch(Exception e)
{
label.Text = "Error: " + e.Message;
return;
}
label.Text = "Success!";
Label text does not get set to "Please Wait..." before the operation.
I solved this using another thread for the operation, but it gets hairy and I'd like to simplify the code.
At first I wondered why the OP hadn't already marked one of the responses as the answer, but after trying it myself and still have it not work, I dug a little deeper and found there's much more to this issue then I'd first supposed.
A better understanding can be gained by reading from a similar question: Why won't control update/refresh mid-process
Lastly, for the record, I was able to get my label to update by doing the following:
private void SetStatus(string status)
{
lblStatus.Text = status;
lblStatus.Invalidate();
lblStatus.Update();
lblStatus.Refresh();
Application.DoEvents();
}
Though from what I understand this is far from an elegant and correct approach to doing it. It's a hack that may or may not work depending upon how busy the thread is.
Call Application.DoEvents() after setting the label, but you should do all the work in a separate thread instead, so the user may close the window.
Call label.Invalidate and then label.Update() - usually the update only happens after you exit the current function but calling Update forces it to update at that specific place in code.
From MSDN:
The Invalidate method governs what gets painted or repainted. The Update method governs when the painting or repainting occurs. If you use the Invalidate and Update methods together rather than calling Refresh, what gets repainted depends on which overload of Invalidate you use. The Update method just forces the control to be painted immediately, but the Invalidate method governs what gets painted when you call the Update method.
If you only need to update a couple controls, .update() is sufficient.
btnMyButton.BackColor=Color.Green; // it eventually turned green, after a delay
btnMyButton.Update(); // after I added this, it turned green quickly
I've just stumbled over the same problem and found some interesting information and I wanted to put in my two cents and add it here.
First of all, as others have already mentioned, long-running operations should be done by a thread, which can be a background worker, an explicit thread, a thread from the threadpool or (since .Net 4.0) a task: Stackoverflow 570537: update-label-while-processing-in-windows-forms, so that the UI keeps responsive.
But for short tasks there is no real need for threading although it doesn't hurt of course.
I have created a winform with one button and one label to analyze this problem:
System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
label1->Text = "Start 1";
label1->Update();
System::Threading::Thread::Sleep(5000); // do other work
}
My analysis was stepping over the code (using F10) and seeing what happened. And after reading this article Multithreading in WinForms I have found something interesting. The article says at the bottom of the first page, that the UI thread can not repaint the UI until the currently executed function finishes and the window is marked by Windows as "not responding" instead after a while. I have also noticed that on my test application from above while stepping through it, but only in certain cases.
(For the following test it is important to not have Visual Studio set to fullscreen, you must be able to see your little application window at the same time next to it, You must not have to switch between the Visual Studio window for debugging and your application window to see what happens. Start the application, set a breakpoint at label1->Text ..., put the application window beside the VS window and place the mouse cursor over the VS window.)
When I click once on VS after app start (to put the focues there and enable stepping) and step through it WITHOUT moving the mouse, the new text is set and the label is updated in the update() function. This means, the UI is repainted obviously.
When I step over the first line, then move the mouse around a lot and click somewhere, then step further, the new text is likely set and the update() function is called, but the UI is not updated/repainted and the old text remains there until the button1_click() function finishes. Instead of repainting, the window is marked as "not responsive"! It also doesn't help to add this->Update(); to update the whole form.
Adding Application::DoEvents(); gives the UI a chance to update/repaint. Anyway you have to take care that the user can not press buttons or perform other operations on the UI that are not permitted!! Therefore: Try to avoid DoEvents()!, better use threading (which I think is quite simple in .Net).
But (#Jagd, Apr 2 '10 at 19:25) you can omit .refresh() and .invalidate().
My explanations is as following: AFAIK winform still uses the WINAPI function. Also MSDN article about System.Windows.Forms Control.Update method refers to WINAPI function WM_PAINT. The MSDN article about WM_PAINT states in its first sentence that the WM_PAINT command is only sent by the system when the message queue is empty. But as the message queue is already filled in the 2nd case, it is not send and thus the label and the application form are not repainted.
<>joke> Conclusion: so you just have to keep the user from using the mouse ;-) <>/joke>
you can try this
using System.Windows.Forms; // u need this to include.
MethodInvoker updateIt = delegate
{
this.label1.Text = "Started...";
};
this.label1.BeginInvoke(updateIt);
See if it works.
After updating the UI, start a task to perform with the long running operation:
label.Text = "Please Wait...";
Task<string> task = Task<string>.Factory.StartNew(() =>
{
try
{
SomewhatLongRunningOperation();
return "Success!";
}
catch (Exception e)
{
return "Error: " + e.Message;
}
});
Task UITask = task.ContinueWith((ret) =>
{
label.Text = ret.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());
This works in .NET 3.5 and later.
It's very tempting to want to "fix" this and force a UI update, but the best fix is to do this on a background thread and not tie up the UI thread, so that it can still respond to events.
Try calling label.Invalidate()
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invalidate(VS.80).aspx
Think I have the answer, distilled from the above and a little experimentation.
progressBar.Value = progressBar.Maximum - 1;
progressBar.Maximum = progressBar.Value;
I tried decrementing the value and the screen updated even in debug mode, but that would not work for setting progressBar.Value to progressBar.Maximum, because you cannot set the progress bar value above the maximum, so I first set the progressBar.Value to progressBar.Maximum -1, then set progressBar.Maxiumum to equal progressBar.Value. They say there is more than one way of killing a cat. Sometimes I'd like to kill Bill Gates or whoever it is now :o).
With this result, I did not even appear to need to Invalidate(), Refresh(), Update(), or do anything to the progress bar or its Panel container or the parent Form.
myControlName.Refresh() is a simple solution to update a control before moving on to a "SomewhatLongRunningOperation".
From: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.update?view=windowsdesktop-6.0
There are two ways to repaint a form and its contents:
You can use one of the overloads of the Invalidate method with the Update method.
You can call the Refresh method, which forces the control to redraw itself and all its children. This is equivalent to setting the Invalidate method to true and using it with Update.
The Invalidate method governs what gets painted or repainted. The Update method governs when the painting or repainting occurs. If you use the Invalidate and Update methods together rather than calling Refresh, what gets repainted depends on which overload of Invalidate you use. The Update method just forces the control to be painted immediately, but the Invalidate method governs what gets painted when you call the Update method.
I had the same problem with property Enabled and I discovered a first chance exception raised because of it is not thread-safe.
I found solution about "How to update the GUI from another thread in C#?" here https://stackoverflow.com/a/661706/1529139 And it works !
When I want to update the UI in "real-time" (or based on updates to data or long running operations) I use a helper function to "simplify" the code a bit (here it may seem complex, but it scales upward very nicely). Below is an example of code I use to update my UI:
// a utility class that provides helper functions
// related to Windows Forms and related elements
public static class FormsHelperFunctions {
// This method takes a control and an action
// The action can simply be a method name, some form of delegate, or it could be a lambda function (see: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions)
public static void InvokeIfNeeded(this Control control, Action action)
{
// control.InvokeRequired checks to see if the current thread is the UI thread,
// if the current thread is not the UI thread it returns True - as in Invoke IS required
if(control.InvokeRequired)
{
// we then ask the control to Invoke the action in the UI thread
control.Invoke(action);
}
// Otherwise, we don't need to Invoke
else
{
// so we can just call the action by adding the parenthesis and semicolon, just like how a method would be called.
action();
}
}
}
// An example user control
public class ExampleUserControl : UserControl {
/*
//
//*****
// declarations of label and other class variables, etc.
//*****
//
...
*/
// This method updates a label,
// executes a long-running operation,
// and finally updates the label with the resulting message.
public void ExampleUpdateLabel() {
// Update our label with the initial text
UpdateLabelText("Please Wait...");
// result will be what the label gets set to at the end of this method
// we set it to Success here to initialize it, knowing that we will only need to change it if an exception actually occurs.
string result = "Success";
try {
// run the long operation
SomewhatLongRunningOperation();
}
catch(Exception e)
{
// if an exception was caught, we want to update result accordingly
result = "Error: " + e.Message;
}
// Update our label with the result text
UpdateLabelText(result);
}
// This method takes a string and sets our label's text to that value
// (This could also be turned into a method that updates multiple labels based on variables, rather than one input string affecting one label)
private void UpdateLabelText(string value) {
// call our helper funtion on the current control
// here we use a lambda function (an anonymous method) to create an Action to pass into our method
// * The lambda function is like a Method that has no name, here our's just updates the label, but it could do anything else we needed
this.InvokeIfNeeded(() => {
// set the text of our label to the value
// (this is where we could set multiple other UI elements (labels, button text, etc) at the same time if we wanted to)
label.Text = value;
});
}
}

Categories

Resources