I'm trying to prevent the GUI from freezing, because of a low timer interval and too much to process in the Timer.Tick event handler.
I've been googling a while and I understood that I cannot update UI from any other thread other than the UI thread.
So, what about if you are using lots of controls under Timer1.Tick?
How can I update a Label when the data is downloaded with WebClient with a timer, you don't want to lower the interval too much and keep the UI responsive at the same time?
I receiver Cross Thread violation exceptions when I access UI elements, a ListBox1 and a RichTextBox.
What is the correct way to update the UI with a timer and/or a Thread without causing cross threat exceptions?
You have different ways to update UI elements from a Thread other than the UI Thread.
You can use the
InvokeRequired/Invoke()pattern (meh), call the asynchronousBeginInvoke()method,Post()to the SynchronizationContext, maybe mixed with an AsyncOperation + AsyncOperationManager (solid BackGroundWorker style), use an async callback etc.There's also the
Progress<T>class and itsIProgress<T>interface.This class provides a quite simplified way to capture the
SynchronizationContextwhere the class object is created andPost()back to the captured execution context.The
Progress<T>delegate created in the UI Thread is called in that context. We just need to pass theProgress<T>delegate and handle the notifications we receive.You're downloading and handling a string, so your
Progress<T>object will be aProgress(Of String): so, it will return a string to you.The Timer is replaced by a Task that executes your code and also delays its actions by a Interval that you can specify, as with a Timer, here using Task.Delay([Interval]) between each action. There's a StopWatch that measures the time a download actually takes and adjusts the Delay based on the Interval specified (it's not a precision thing, anyway).
▶ In the sample code, the download Task can be started and stopped using the
StartDownload()andStopDownload()methods of a helper class.The
StopDownload()method is awaitable, it executes the cancellation of the current tasks and disposes of the disposable objects used.▶ I've replaced WebClient with HttpClient, it's still quite simple to use, it provides async methods that support a
CancellationToken(though a download in progress requires some time to cancel, but it's handled here).▶ A Button click initializes and starts the timed downloads and another one stops it (but you can call the
StopDownload()method when the Form closes, or, well, whenever you need to).▶ The
Progress<T>delegate is just a Lambda here: there's not much to do, just fill a ListBox and scroll a RichTextBox.You can initialize the helper class object (it's named
MyDownloader: of course you will pick another name, this one is ridiculous) and call itsStartDownload()method, passing theProgress<T>object, theUriand theIntervalbetween each download.The helper class: