patterncsharpMinor
Keep the sequential nature while updating the UI of the progress of the HTTP request
Viewed 0 times
thewhilekeepupdatingrequestnaturesequentialprogresshttp
Problem
Let's say that I have a method that makes an HTTP request that will take a long time to finish. While that's happening the UI is not updating because I'm doing it in the UI's thread.
One solution is to:
That's all nice and good, but it means that I went from code that was sequential in nature to something that has callbacks or something similar (promises).
So, I'm trying to keep the sequential nature while updating the UI. Having something like await/async would help here, but even in that case the caller has to be aware of this (plus I need .NET 4.5, let's assume that this is not an option). So I came up with something that keep the sequential nature of the original call, doesn't affect the caller of the function makes the HTTP request but updates the UI.
So, here it is:
`public class Async
{
public static T Run(Func action)
{
var worker = new BackgroundWorker();
var error = new Exception[] {null};
var result = new[] {default(T)};
// The original call will run in a separate thread.
worker.DoWork += (sender, ea) => { result[0] = action(); };
worker.RunWorkerCompleted += (sender, ea) => { error[0] = ea.Error; };
worker.RunWorkerAsync();
// While the work is being done in a separate thread, update the UI's event loop (is this safe???)
while (worker.IsBusy)
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { }));
Thread.Sleep(20);
}
// Re raise the exception if needed
if (error[0] != null)
throw error[0];
return result[0];
}
}
//Usage
var someVariable = 123;
var responseA = Async.Run(DoSuperLongTask);
var responseB = Async.Run(() =>
{
return DoSuperComplicatedTask(
One solution is to:
- Show the "Loading" animation.
- Start the HTTP request on a thread.
- On the completion callback stop the "Loading" animation and work on the response.
That's all nice and good, but it means that I went from code that was sequential in nature to something that has callbacks or something similar (promises).
So, I'm trying to keep the sequential nature while updating the UI. Having something like await/async would help here, but even in that case the caller has to be aware of this (plus I need .NET 4.5, let's assume that this is not an option). So I came up with something that keep the sequential nature of the original call, doesn't affect the caller of the function makes the HTTP request but updates the UI.
So, here it is:
`public class Async
{
public static T Run(Func action)
{
var worker = new BackgroundWorker();
var error = new Exception[] {null};
var result = new[] {default(T)};
// The original call will run in a separate thread.
worker.DoWork += (sender, ea) => { result[0] = action(); };
worker.RunWorkerCompleted += (sender, ea) => { error[0] = ea.Error; };
worker.RunWorkerAsync();
// While the work is being done in a separate thread, update the UI's event loop (is this safe???)
while (worker.IsBusy)
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { }));
Thread.Sleep(20);
}
// Re raise the exception if needed
if (error[0] != null)
throw error[0];
return result[0];
}
}
//Usage
var someVariable = 123;
var responseA = Async.Run(DoSuperLongTask);
var responseB = Async.Run(() =>
{
return DoSuperComplicatedTask(
Solution
Good you have a
Call
This applies to
Hope this helped.
BackgroundWorker. If I understood correctly, let's say you want to update a button, whether to enable it or not. you can use this:delegate void EnableButton(Button b, bool enable);
public void ActuallyEnableButton(Button b, bool enable)
{
if (b.InvokeRequired)
{
EnableButton del = ActuallyEnableButton;
b.Invoke(del, new object[] { b, enable });
//in some cases add "return" statement
}
b.Enabled = enable;
}Call
ActuallyEnableButton(btn, true) for example, inside DoWork event of BackgroundWorker.This applies to
Label, TextBox, ComboBox, ListView, ProgressBar, etc. No need to use this code if you want to update ToolStripStatusLabel and ToolStripProgressBar.Hope this helped.
Code Snippets
delegate void EnableButton(Button b, bool enable);
public void ActuallyEnableButton(Button b, bool enable)
{
if (b.InvokeRequired)
{
EnableButton del = ActuallyEnableButton;
b.Invoke(del, new object[] { b, enable });
//in some cases add "return" statement
}
b.Enabled = enable;
}Context
StackExchange Code Review Q#46199, answer score: 2
Revisions (0)
No revisions yet.