I am fairly new to reactive UI. I am using it in my app extensively for async programming etc.
I have a question. I have a method in my ViewModel which is async and which "awaits" for a task to complete. On completion of this task, I would like to notify my view (a UserControl) so it can dynamically add some more content/UserControls, to say, a DockPanel.
What is the best way of doing this using ReactiveUI or RX? I could use C# event mechanism , etc. but I want to continue down the RX path. I set a boolena property in my VM when the async method has "completed" (i.e. returned from await).
I then want to observe for this boolean property (defined in my VM) in my "View"..so I can attach a handler in my "View" which will dynamically create some UserControls, e.g.
this.viewModel.ObservableForProperty(x => x.DataLoaded)
.Subscribe(async _ => await this.MyViewHandler());
// this does not compile as the delegate is not IObserver type in my view it says
Any guidance will be much appreciated, many thanks.
You've mostly got the right idea, just need some work on the syntax:
this.WhenAnyValue(x => x.ViewModel.DataLoaded)
.Where(x => x == true)
.Subscribe(_ => MyViewHandler());
The problem with your example code is that as the compiler says, you are not passing a valid IObserver implementation to the Subscribe method. You are actually passing an Func<boolean, Task> where it is expecting an Action<boolean> implementing the IObserver.OnNext.
I haven't tried ReactiveUI, but I think you can accomplish but you intend with either Task Continuation or with the IObserver.OnCompleted. A couple ideas are:
Using Task Continuation you'd launch another task once the one you mentioned has finished. You can do this by appending a .ContinueWith call to your task. Keep in mind that code from the continuation task modifying the UI must be dispatched to the UI thread from the continuation task (either using the Dispatcher or by passing the proper TaskScheduler to ContinueWith).
With RX, you could create a sequence for your task with the proper Observable.Create factory method or simply using the Task.ToObservable extension methods, then subscribe to it and do whatever you want on the OnCompleted handler.
Related
When we are dealing with async tasks, the task consists of multiple method calls (possibly of other classes) which in turn consist of yet further method calls. We could call this a tree. Do all methods have to be of type async task for the original task to truly behave async?
Would the answer be true for any kind of background task of other similar languages, mostly Java as well?
(In C#, once I had one of my methods somewhere in this tree get into an infinite loop (talk about a long running task!), yet sadly, the original async task's isRunning property returned false.)
Do all methods have to be of type async task for the original task to truly behave async?
In order to behave asynchronously, an async method must have an await statement for an operation that is not already completed.
I think my async intro blog post would be helpful for you.
Would the answer be true for any kind of background task of other similar languages, mostly Java as well?
Yes.
sadly, the original async task's isRunning property returned false
I assume you mean that the TaskStatus was not TaskStatus.Running. This is normal and expected, since asynchronous tasks are Promise Tasks, not Delegate Tasks (see my blog for more info).
The short answer is no. Async means that work being done by another process can be handed off to that process and so not block the calling thread. All the better if those processes don’t reside on the same machine, since that work will occupy very little compute or IO at the caller. This is achieved by suspending method execution using the async/await mechanism, which promises to resume on some synchronisation context once completed. So, why the overview?
Because this means that we can and should judiciously choose those operations that should be async, and so apply the await keyword in an async method. Some won’t need it, since they are lightweight and adding async to them may even add compute time to them, due to the creation of the async state machine. So the operations in a method can often be a mixture of asynchronous and synchronous code.
And this in turn means that some methods would use the Task return type with async/await, and some will be regular, synchronous methods.
No, they don't have to. Simple example, in a Forms application this
button.Click += async (_, __) =>
{
await Task.Run(() => MyClass.SomeTimeconsumingMethod());
};
still lets you move the window during the execution of SomeTimeconsumingMethod, whereas this one
button.Click += (_, __) =>
{
MyClass.SomeTimeconsumingMethod();
};
doesn't let you do it.
The only requirement for using the await keyword is that the method you are awaiting returns a Task or Task<T>.
The exact implementation of this method (async or return someTask) has no influence on the correctness of the code, although it may influence the function.
Any normal code can run in an async method alongside your await calls. The only significant restriction is that out and ref are not allowed.
Do all methods have to be of type async task for the original task to truly behave async
It depends on what do you mean by "all" word.
Some APIs must not be asynchronous. Think about List<T>.Add, for example. Do you really want it to be asynchronous?
Some APIs should be asynchronous, but there's no asynchronous counterpart (e.g. SMO, or File static class).
Ideally you should do "async all the way", when talking about IO-bound operations. But IRL you can face with violation of this rule, when some part of your async method chain will execute IO-bound operation synchronously.
If I write a simple function I can get a result immediately. If I use async/await and return a Task - the method will kinda return when it's done with the task, but what if I need to write a method that needs to return immediately, but then continue updating the result and potentially eventually complete the task? Also what if I want to expose it outside a WinRT Component library for consumption in components in other languages? How would I do it in C# and how would I do it in C++/CX? Or JS perhaps?
Example 1:
I want to expose a property that returns an ImageSource so I can immediately bind it from my MVVM view model to the XAML view. The method to load the ImageSource is going to be in a separate class that is exposed outside a WinRT Component (it is a public method). Now I want that method to be awaitable, or at least somehow return a task I can await but also immediately return the ImageSource so the property I call it from can immediately return since properties can't be async. The caller doesn't know what type the ImageSource will be so it cannot instantiate it since ImageSource is virtually an abstract type and is typically represented as a BitmapImage or WriteableBitmap and in my case both can be returned from the method. Obviously the method itself immediately knows whether it is going to return either of the types of objects, but it takes some time to read/create and or decode the image.
I'm thinking the signature might be something like this in C#
public async Task<ImageSource> GetImage(
object key,
out ImageSource bitmap,
CancellationToken cancellationToken)
and I would simply not await the result of the method in the property accessor, but I'm thinking I'll be able to return the bitmap argument immediately, while when called elsewhere or event elsewhere in the code of my view model I'll be able to await or cancel the task.
Example 2:
I want to be able to list files from a disk and get a task that is complete when all files have been listed, but immediately return an IObservableVector of view models representing the files for use in my XAML UI that updates as pages of the files are loaded asynchronously.
Here I would probably do something similar:
public async Task<int> GetImages(
object queryParemeters,
out ObservableCollection<CustomFileInfoType> files,
CancellationToken cancellationToken)
Problems
Now the above look almost good, but I don't think I can expose a TPL Task outside a WinRT Component since Task is not a WinRT type, so I'd probably gave an internal method like the above and a public one that wraps the result as an IAsyncOperation by calling AsyncInfo.Run(), passing the task and cancellation token. ObservableCollection is also .NET only, so I'd probably need to create a wrapper around it that implements an IObservableVector since I don't think one is available in .NET. There are probably other potential problems with those and I am not sure if this design is right.
Then also - how would I do all this in C++/CX? Or JS?
async is built on the notion of an asynchronous operation, with a definite beginning and ending. At the end, there may be a single result. That's it. Note that async methods may not have out parameters because they don't fit into this model.
If you want a stream of values, then use Reactive Extensions. There's an interesting RxUI library that nicely marries observables with MVVM patterns.
That said, I don't think either of your examples actually require observables (though you certainly could move to Rx if you wanted). I address your first example (data-bound async properties) on my blog; the short answer is to use a wrapper for Task<T> that implements INotifyPropertyChanged like this one:
// Service
public async Task<ImageSource> GetImage(object key, CancellationToken cancellationToken);
// ViewModel
INotifyTaskCompletion<ImageSource> Image { get; private set; }
...
Image = NotifyTaskCompletion.Create(GetImage(key, token));
// View
<Image Source="{Binding Image.Result}" />
Regarding your second example, this can be done fairly easily by treating the new items as progress updates from the async method:
// Service
public async Task<int> GetImages(object queryParemeters,
CancellationToken cancellationToken,
IProgress<CustomFileInfoType> progress);
// ViewModel
var collection = new ObservableCollection<CustomFileInfoType>();
var progress = new Progress<CustomFileInfoType>(x => collection.Add(x));
await GetImages(query, token, progress);
Exposing these types is something else completely. WinRT components must expose WinRT types. I recommend you write the basic logic (service and possibly ViewModel) using pure async/await and then do the translation separately. As you noted, AsyncInfo.Run will translate Task to IAsyncOperation, and there isn't a built-in translator for ObservableCollection to IObservableVector (though it isn't hard to write, and there are several available via Google).
Then also - how would I do all this in C++/CX? Or JS?
I have no idea on that one. You'll probably have to write your own equivalent for NotifyTaskCompletion on those platforms, or just use callbacks.
I rewrote some old async code of mine that makes that makes SOAP calls. The fetch() method would go out, get the result from the SOAP interface, and then add it to a DataTable that is bound to my WPF view. The new code uses Reactive Extensions to get a list of strings and creates an IObservable from the list. I thought it would return the results asynchronously, but the entire UI locks up until the entire result set is ready. I'm new to Reactive Extensions so I'm hoping I'm just missing something simple.
The Code:
(from click event)
private void fetchSoapRows()
{
var strings = (txtInput.Text.Split('*')).ToObservable();
strings.Subscribe(s=> SoapQueryEngine.Fetch(s));
}
Also, does anyone know how I could write a test to make certain this method doesn't block the application in the future?
There are two parts to an observable query, the Query itself and the Subscription.
Your Query is an IEnumerable<string> producing values as fast as the computer can do it.
Your Subscription is
SoapQueryEngine.Fetch(s);
This runs Fetch for each string produced by the Query in the Subscriber thread which tends to be the thread where you're setting up your Subscription (although it isn't necessarily).
The issue has to do with the intention and design of Rx. It's intended that the Query is the long-running process and the Subscription is a short method that deals with the results. If you want to run a long running function as an Rx Observable your best option is to use Observable.ToAsync.
You should also take a look at this question to see a similar problem which shows more of what's going on in the background.
There is nothing inherently concurrent about Rx. If you want to make your calls to Fetch you will need to change SoapQueryEngine so that it is async or call it on another thread and then bring the results back to the UI thread.
Try this way. Instead of subscribing to the event text changed event, create an observable on the event and observe it on the thread pool:
Observable.FromEventPattern(<subscribe event>, <unsubscribe event>)
.ObserveOn(ThreadPoolScheduler.Instance)
.SelectMany(s => s.Split('*'))
.Subscribe(s=> SoapQueryEngine.Fetch(s));
I'm trying to provide a functionality of having two Methods one called StartTask(action mymethod)
and the other called StopTask();
problem is the action has to have access to the CancellationTokenSource to check for cancellation and exit the method (return) which is not really what i want the method could be in another component or layer , i cant push every Method to have access to that cancellationtokensource,
i cant push the designer/developer of the component which have the process method to check for cancellation and return.
is there is any way to have something like this , i know it sound strange and inapplicable , just thought of asking.
this is the best i got:
CancellationTokenSource cancellationTokenSource;
private void button1_Click(object sender, EventArgs e)
{
cancellationTokenSource = new CancellationTokenSource();
Task t = new Task(() => Dowork(CancellationAction), cancellationTokenSource.Token, TaskCreationOptions.LongRunning);
t.Start();
}
private bool CancellationAction()
{
if (cancellationTokenSource.IsCancellationRequested)
{
label1.Invoke(new MethodInvoker(() =>
{
label1.Text = "Cancellation Requested!";
}));
return true;
}
return false;
}
private void Dowork(Func<bool> Return)
{
int x = 1;
while (true)
{
x++;
label1.Invoke(new MethodInvoker(() =>
{
label1.Text = x.ToString();
}));
Thread.Sleep(1000);
if (Return())
{
return;
}
}
}
problem with this is DoWork now has to have one parameter which is func , but what if the method already takes other parameters ? the creation of task will be in another class which might not have any idea what parameters to pass beside CancellationAction
If the component does not provide a way to cancel one of its running tasks, then the caller should not be able to cancel it. It could leave the application/database/anything in an unknown state.
So basically the lower level component should provide the caller with a way to cancel a task (ManualResetEvent, CancelAsync method like the BackgroundWorker, etc.). Otherwise the caller should wait for it to finish.
If the lower level component does not provide such a feature, it is most of the time considered as bad design.
I'm not sure that I entirely understand your question, but I'll take a stab at it. It seems like you're trying to solve two problems at once here.
First you're trying to pass parameters to an asynchronous thread and/or cancel that thread (very similar issues). As others have stated BackgroundWorker already handles canceling. That implementation is similar to passing any argument to your thread. If I were replicating that functionality for instance I'd add a Cancel property or method to my worker thread that any other component could call and check a backing value in my main thread loop. No reason to do that for canceling threads these days, just an example of passing and using values to a worker thread.
The other problem that it looks like you need to solve is how to send messages between different parts of your application that shouldn't otherwise need to reference each other. Typically I've seen this done with a service provider of some sort. Implement an interface on a context or common model that all components receive an instance of or have easy access to. The interface should contain any events, methods and properties so the different components can communicate.
E.g. (probably a bad example but...) If my grammar checking routine should cancel when a document is closed, I would define a DocumentClosing event and OnDocumentClosing method on an IDocumentService interface and implement that interface in an appropriate context/model. When creating my document viewer UI component and grammar checker thread component I would inject an instance of the context/model typed as the interface. When the document viewer starts to close the document, it calls the OnDocumentClosing method from the interface. When the thread is created it would attach to the DocumentClosing event and if the event fires a flag is set. Then at intervals while checking grammar, I would check the flag and cancel as appropriate.
This sort of implementation gives you the flexibility to have any component trigger appropriate events and any other component react to them regardless of where in your application the components are used. In fact, this approach is useful even in synchronous situations such as menu items changing state in response to application events. It allows for easy unit testing of all your components. And the segregation of responsibility means that you can easily change any of the trigger points and responses as needed.
Why don't you use BackgroundWorkerThread or other threading mechanism?
Is there a particular reason for using Task Parallel Library?
BackgroundWorkerThread will give you a change to cancel the task and then respond to cancellation.
I am working on an WPF application that uses a BusinessLogic layer (currently a single dll) in which I created my BL methods that will be called directly from the UI. Each BL manager is resolved with Unity (thinking on switching to MEF though...). BL classes implements a specific interface that have of course apropriate methods.
Now, what I want is to create (or rather to GENERATE) a new asynchronous-aspect-like assembly (or more...) that should have similar methods/operations defined as in my original assembly (the same parameters...) and also a callback delegate as a parameter.
So basically I want async methods to be generated with some framework out there...
Besides the usual call to:
User userBO = Resolve().Login("name", "pass");
I'd like to use something similar with:
Resolve().Login("name", "pass", delegate(object, SomeArgs e) { User userBO = e.Args....};
Now, I want this assembly to be generated instead of writing new eventArgs and delegates for each method.
I am aware that PostSharp could help in AOP task, but I coulnd't find anything regarding this code generation mechanism in a new dll for asynchronous methods.
Is there a way to achieve this using a third party tool or do I have to rewrite the whole async thing manually?
Any ideas are welcome.
Thank you.
I'm not aware of a tool that will do this for you, but there's an easy way to wrap them in Task objects. This is easier at least than manually defining Async methods and event callbacks.
The general concept is to run the method as a Task and then schedule a task continuation to the UI thread.
First, define a scheduler (you don't need to do this every time; it could be a global var or a window-level var):
TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();
then when you want to call a method and handle its return value:
var bll = Resolve();
Task.Factory.StartNew(_ => bll.Login("name", "pass"))
.ContinueWith(task =>
{
// Note: accessing Result will raise any exceptions thrown by Login
User userBO = task.Result;
...
}, ui);
It's not quite as pretty as your suggested syntax, but it's usable. The task continuation passed to ContinueWith will run on the UI thread, so it is safe to update the UI or any databound objects.
Task objects also fully support other common asynchronous scenarios, in particular cancellation and progress reporting.
Since this approach doesn't actually add events to the class, it should be possible to write a T4 template to generate extension methods for you (e.g., LoginTask(string username, string password, Action<Task<User>> continuation)).