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
SynchronizationContext
where 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, theUri
and theInterval
between each download.The helper class: