I would like to track the progress of a download taking place on a separate thread. I know that System.Net.WebClient has a DownloadStringAsync method, but it doesn't work directly with the new TPL types (TaskFactory, Task, etc.).
Can progress be tracked using the HttpRequest and HttpResponse classes?
What's the best class for tracking progress? The less overhead the better.
Are there times when the size of the response is unknown, aka, progress can't be tracked?
What's the best way to synchronize with the UI thread whenever progress is made?
Most examples show Tasks updating the UI only after the entire task is complete. These examples use continuations taking a UI synchronization context that avoids needing to work with a Dispatcher directly.
The idea is to show a grid view (in WPF) with all the downloads with progress bars. I am going to adding new rows and updating progress bars all the time. I'm trying to avoid turning this code into a mess.
DownloadStringAsync and the other event methods work very well with TPL in .NET 4.0 (check for EAP and TPL). In general, TPL does support event async programming through the TaskCompletionSource. The Begin/EndXXX model (APM) is supported through the Task.FromAsync method. You can find a detailed description TPL and Traditional .NET Asynchronous Programming.
The ParallelExtensionExtras library has a set of WebClient extensions methods like DownloadStringTask that return a task which completes when the appropriate event is fired.
The following code will create a Task that will complete when download finishes:
public Task<string> DownloadStringTask(WebClient client,Uri uri)
{
var tcs = new TaskCompletionSource<string>();
client.DownloadStringCompleted += (o, a) => tcs.SetResult(a.Result);
client.DownloadStringAsync(uri);
return tcs.Task;
}
As for updating the UI, you can easily use the DownloadProgressChanged event to provide feedback,eg:
using (var client = new WebClient())
{
client.DownloadProgressChanged += (o, a) => Console.WriteLine("{0}",a.ProgressPercentage);
var task = DownloadStringTask(client,new Uri("http://www.stackoverflow.com"));
var write=task.ContinueWith(t => Console.WriteLine("Got {0} chars", t.Result.Length));
write.Wait();
Console.ReadKey();
}
If you use data binding to provide the progress values to your progress bars, you can just update the progress value properties. If you update the progress bars directly (not a good idea), you will have to marshal the call to the UI thread using the progress bar's dispatcher, eg. like this
void UpdateProgress(int percent)
{
if (progressBar1.CheckAccess())
progressBar1.Value = percent;
else
{
progressBar1.Dispatcher.Invoke(new Action(()=>UpdateProgress(percent)));
}
}
....
client.DownloadProgressChanged += (o, a) => UpdateProgress(a.ProgressPercentage);
Related
I am in a similar situation as this poster (What's the best way to create a new UI thread and call back methods on the original thread?)
I have an API object which I would like to perform lengthy calculations on, however any properties or methods of this object must be accessed on the current thread (which is the UI thread) or else I get "Accessing disposed TPS.NET DataObject" exceptions
Is there an elegant way of accomplishing this using F# async workflows or will I be stuck managing thread dispatchers as in his solution.
For reference, here is his solution to the issue:
public class Plugin
{
public void Run(Context context)
{
// Get the application's UI thread dispatcher
var dispatcher = Dispatcher.CurrentDispatcher;
// Create a dispatcher frame to push later
var frame = new DispatcherFrame();
// Create a new UI thread (using an StaTaskScheduler)
Task.Factory.StartNew(async () =>
{
var window = new MyWindow();
// The Click event handler now uses the original
// thread's dispatcher to run the slow method
window.MyButton.Click += async (o, e) =>
await dispatcher.InvokeAsync(() => context.SlowMethod());
window.ShowDialog();
// When the window is closed, end the dispatcher frame
frame.Continue = false;
}, CancellationToken.None, TaskCreationOptions.None, new StaTaskScheduler(1));
// Prevent exiting this Run method until the frame is done
Dispatcher.PushFrame(frame);
}
}
Without know the exact details I would suggest having the Click handler on the main thread and do the following:
Copy any data needed off the UI into an F# record and passes this into an async workflow
Return immediately after putting the UI into a 'loading' state
The following code is untested but should put you on the right track:
//Get the context of the UI
let context = System.Threading.SynchronizationContext.Current
//Gather any needed data from the UI into immutable F# records
//Put the UI into a 'loading' state
async {
// Do work on a different thread
do! Async.Sleep 1000
let x = 1
// Switching back to the UI
do! Async.SwitchToContext context
//Update UI
return ()
}
|> Async.Start
This link should also provide some useful information http://tomasp.net/blog/async-non-blocking-gui.aspx/
EDIT:
If you need to go back and forth between the UI thread and a background thread to gather additional information in the async workflow you can make alternating calls between do! Async.SwitchToThreadPool() and do! Async.SwitchToContext context
My questions are many. Since I saw. NET 4.5, I was very impressed. Unfortunately all my projects are .NET 4.0 and I am not thinking about migrating. So I would like to simplify my code.
Currently, most of my code that usually take enough time to freeze the screen, I do the following:
BackgroundWorker bd = new BackgroundWorker();
bd.DoWork += (a, r) =>
{
r.Result = ProcessMethod(r.Argument);
};
bd.RunWorkerCompleted += (a, r) =>
{
UpdateView(r.Result);
};
bd.RunWorkerAsync(args);
Honestly, I'm tired of it. And that becomes a big problem when there is a logic complex user interaction.
I wonder, how to simplify this logic? (Remember that I'm with. Net 4.0) I noticed a few things by google, but not found anything easy to implement and suitable for my needs.
I thought this solution below:
var foo = args as Foo;
var result = AsyncHelper.CustomInvoke<Foo>(ProcessMethod, foo);
UpdateView(result);
public static class AsyncHelper
{
public static T CustomInvoke<T>(Func<T, T> func, T param) where T : class
{
T result = null;
DispatcherFrame frame = new DispatcherFrame();
Task.Factory.StartNew(() =>
{
result = func(param);
frame.Continue = false;
});
Dispatcher.PushFrame(frame);
return result;
}
}
I am not sure about the impact is on manipulating the dispatcher frame.
But I know That it would work very well, for example, I could use it in all the events of controls without bothering to freeze the screen.
My knowledge about generic types, covariance, contravariance is limited, maybe this code can be improved.
I thought of other things using Task.Factory.StartNew and Dispatcher.Invoke, but nothing that seems interesting and simple to use. Can anyone give me some light?
You should just use the Task Parallel Library (TPL). The key is specifying the TaskScheduler for the current SynchronizationContext for any continuations in which you update the UI. For example:
Task.Factory.StartNew(() =>
{
return ProcessMethod(yourArgument);
})
.ContinueWith(antecedent =>
{
UpdateView(antecedent.Result);
},
TaskScheduler.FromCurrentSynchronizationContext());
Aside from some exception handling when accessing the antecedent's Result property, that's all there is too it. By using FromCurrentSynchronizationContext() the ambient SynchronizationContext that comes from WPF (i.e. the DispatcherSynchronizationContext) will be used to execute the continuation. This is the same as calling Dispatcher.[Begin]Invoke, but you are completely abstracted from it.
If you wanted to get even "cleaner", if you control ProcessMethod I would actually rewrite that to return a Task and let it own how that gets spun up (can still use StartNew internally). That way you abstract the caller from the async execution decisions that ProcessMethod might want to make on its own and instead they only have to worry about chaining on a continuation to wait for the result.
UPDATE 5/22/2013
It should be noted that with the advent of .NET 4.5 and the async language support in C# this prescribed technique is outdated and you can simply rely on those features to execute a specific task using await Task.Run and then execution after that will take place on the Dispatcher thread again automagically. So something like this:
MyResultType processingResult = await Task.Run(() =>
{
return ProcessMethod(yourArgument);
});
UpdateView(processingResult);
How about encapsulating the code that is always the same in a reusable component? You could create a Freezable which implements ICommand, exposes a property of Type DoWorkEventHandler and a Result property. On ICommand.Executed, it would create a BackgroundWorker and wire up the delegates for DoWork and Completed, using the value of the DoWorkEventHandler as event handler, and handling Completed in a way that it sets its own Result property to the result returned in the event.
You'd configure the component in XAML, using a converter to bind the DoWorkEventHandler property to a method on the ViewModel (I assume you've got one), and bind your View to the component's Result property, so it gets updated automatically when Result does a change notification.
The advantages of this solution are: it is reusable, and it works with XAML only, so no more glue code in your ViewModel just for handling BackgroundWorkers. If you don't need your background process to report progress, it could even be unaware that it runs on a background thread, so you can decide in the XAML whether you want to call a method synchronously or asynchronously.
A few months have passed, but could this help you?
Using async/await without .NET Framework 4.5
I'm trying to implement my first application using the MVVM pattern. I've manged to get most things working, but now I'm facing a problem with the following (IMHO pretty common) scenario:
Pressing a Button (View) shall invoke a Method (Model). Using a ICommand (ViewModel) this is pretty easy. But what to do if a time consuming operation has to be executed?
My current solution required me to implement a WorkQueue class containing WorkQueueItems. The WorkQueue has a Thread associated with it which executes the WorkQueueItems. Each WorkQueueItem has a Name, a Status and a Progress which is updated during execution.
Each Window has its own WorkQueue - visualized as StatusBar.
My problem: How can a ViewModel find the appropriate WorkQueue? Do I have to pass the WorkQueue to each ViewModel I create (this would be really be annoying)? Or are there other mechanism I could use?
I'm not really familiar with RoutedCommands - tough the basic concept seems to go into this direction. What'd love to see is a solution where I can bind a WorkQueueItem to a Command/Event which then bubbles up to the containing Window where it is added to the Window's WorkQueue.
I also considered making WorkQueue a Singleton - but this only works if I only have one Window at a time.
With the later .Net Frameworks (4.0+) and WPF you can utilize the System.Threading.Tasks library to provide a lot of this work under the hood.
If say your Command on your needs to update a property on your View Model, but it has to wait for the information, you simply start a task to perform the IO:
this.FindDataCommand = new RelayCommand<string>(
/* ICommand.Execute */
value =>
{
Task.Factory
.StartNew<IEnumerable<Foo>>(() => FindData(value))
.ContinueWith(
task =>
{
this.foundData.Clear();
this.foundData.AddRange(task.Result);
},
TaskScheduler.FromCurrentSynchronizationContext());
},
/* ICommand.CanExecute */
value => !String.IsNullOrWhitespace(value));
Breaking this down into manageable parts, we're starting a new task which calls some method IEnumerable<Foo> FindData(string). This is the plain old boring synchronous code you've always written. Likely it already exists on your view model!
Next we tell the framework to start a new task when that one finishes using ContinueWith, but to do it on the WPF Dispatcher instead. This allows you to avoid the hassles of cross-thread problems with UI elements.
You can extend this for monitoring with a helper class:
public class TaskManager
{
private static ConcurrentDictionary<Dispatcher, TaskManager> _map
= new ConcurrentDictionary<Dispatcher, TaskManager>();
public ObservableCollection<WorkItem> Running
{
get;
private set;
}
public TaskManager()
{
this.Running = new ObservableCollection<WorkItem>();
}
public static TaskManager Get(Dispatcher dispatcher)
{
return _map.GetOrAdd(dispatcher, new TaskManager());
}
// ...
Using this class in XAML would be along the lines of adding its instance to your Window's ViewModel:
public TaskManager CurrentTaskManager
{
get { return TaskManager.Get(Dispatcher.CurrentDispatcher); }
}
// <StatusBarItem Content="{Binding CurrentTaskManager.Running.Count}" />
You would then add a method to your TaskManager to handle the adding of tasks to and from the Running collection:
public Task<TResult> StartNew<TResult>(Func<TResult> work)
{
var task = Task.Factory
.StartNew<TResult>(work);
// build our view model
var workItem = new WorkItem(task);
this.Running.Add(workItem);
// Pass the result back using ContinueWith
return task.ContinueWith(
t => { this.Running.Remove(workItem); return t.Result; },
TaskScheduler.FromCurrentSynchronizationContext());
}
Now we simply change our FindDataCommand implementation:
TaskManager.Get(Dispatcher.CurrentDispatcher)
.StartNew<IEnumerable<Foo>>(() => FindData(value))
.ContinueWith(
task =>
{
this.foundData.Clear();
this.foundData.AddRange(task.Result);
},
TaskScheduler.FromCurrentSynchronizationContext());
The WorkItem class could expose the properties on the Task class to the UI, or it could be extended to encapsulate a CancellationToken to support cancellation in the future.
I'm not sure I got the question right, but I feel that using buil in Dispatcher would solve your problem and you do not need implementing WorkQueue manually since Dispatcher implements such a queue for you and able dispatching "worker items" to the UI/any thred using predefined set of priorities. You can execute an operation either synchronously or asynchronously using Dispatcher.Invoke() or Dispatcher.BeginInvoke()
Useful links:
MSDN Magazine: WPF Threads, Build More Responsive Apps With The Dispatcher
When you have a button, and do something like:
Private Function Button_OnClick
Button.Enabled = False
[LONG OPERATION]
End Function
Then the button will not be grayed, because the long operation prevents the UI thread from repainting the control. I know the right design is to start a background thread / dispatcher, but sometimes that's too much hassle for a simple operation.
So how do I force the button to redraw in disabled state? I tried .UpdateLayout() on the Button, but it didn't have any effects. I also tried System.Windows.Forms.DoEvents() which normally works when using WinForms, but it also had no effect.
The following code will do what you're looking for. However I would not use it. Use the BackgroundWorker class for long time operations. It's easy to use and very stable.
Here the code:
public static void ProcessUITasks() {
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(delegate(object parameter) {
frame.Continue = false;
return null;
}), null);
Dispatcher.PushFrame(frame);
}
Here you will find a sample on how to use the BackgroundWorker.
InvalidateVisual(); #HCL is right... don't do this
Like you say, it is better to start use a background thread / dispatcher and keep the UI thread unblocked. Consider looking at the Reactive Extensions library from Microsoft for high level asynchronous ui programming
In Windows.Forms, you can Button.Refresh().
In Windows.Forms or WPF, you can yield to the message pump to let it redraw. Async/Await were designed to allow you to do this without the nastiness of HCL's answer.
Private Async Function Button_OnClick
Button.Enabled = False
Await Task.Yield
[LONG OPERATION]
End Function
I am using Reactive Extensions to verification of a textbox input.
I am trying to use the .Throttle(TimeSpan.FromMilliseconds(500)).
But when I add the .Throttle() method a cross thread exception is thrown when accessing a UI object in the .Subscribe() method.
It works 100% without the Throttle, why is it breaking?
My code:
var textChangedEvent = Observable.FromEvent<TextChangedEventArgs>(usernameTextbox, "TextChanged")
.Throttle(TimeSpan.FromMilliseconds(500))
textChangedEvent.Subscribe(changed =>
{
TextBox oUsernameTextBox = changed.Sender as TextBox;
//Accessing oUsernameTextBox throws Cross Thread Exception
});
Thanks
-Oliver
By default Throttle uses the ThreadpoolScheduler so events will not arrive on the UI Thread. Since you need the events on the UI thread use:-
var textChangedEvent = Observable.FromEvent<TextChangedEventArgs>(usernameTextbox, "TextChanged")
.Throttle(TimeSpan.FromMilliseconds(500), Scheduler.Dispatcher);
This will put the events back on the UI Thread.
I had to tweak the code a bit to make it work in a LightSwitch (SilverLight 4) application with Rx v1.0.10621 due to some interface changes in Rx since when this question had been asked.
Need to install Rx and to reference System.Reactive and System.Reactive.Windows.Threading assemblies (for LightSwitch this reference go in the Client project).
Then use this code to throttle a the TextChange event on the text box:
(Note: For lightswitch this code goes in the ControlAvailable handler)
var textChangedEvent = Observable
.FromEventPattern<TextChangedEventArgs>(e.Control, "TextChanged")
.Throttle(TimeSpan.FromMilliseconds(500))
.ObserveOnDispatcher();
textChangedEvent.Subscribe(changed =>
{
var tb = changed.Sender as TextBox;
if (tb.Text.Length >= 3) // don't search for keywords shorter than 3 chars
{
// search
}
});