How to call async method from PropertyChanged? - c#

I have an WPF application based on MVVM architecture. I am implementing the common and widely used INotifyPropertyChanged interface on my ViewModels, because I need to react on user interaction.
But how do I perform an asynchronous action (e.g. loading some data) from within the synchronous PropertyChanged event handler without using async void 'hacks'?
Thanks in advance!
EDIT
The main reason why i need to avoid async void is because I am working in an test driven environment. Async void methods are not testable :(

Actually, this is not about async void.
Usually you want to fire async operation and let your property setter return.
Sample snippet:
private string carManufacturerFilter;
public string СarManufacturerFilter
{
get { return carManufacturerFilter; }
set
{
if (carManufacturerFilter != value)
{
carManufacturerFilter = value;
OnPropertyChanged();
// fire async operation and forget about it here;
// you don't need it to complete right now;
var _ = RefreshCarsListAsync();
}
}
}
private async Task RefreshCarsListAsync()
{
// call some data service
var cars = await someDataService.GetCarsAsync(carManufacturerFilter)
.ConfigureAwait(false);
// ...
}
Note, that there are a lot of things to add here:
since this is fire-and-forget approach, you need to block user input until operation is running. In other words, there should be some sort of busy indicator;
you may want to delay async operation firing. This is usually applicable, when there are string properties. You don't want to fire async operation after each char typed by user. Instead it's desirable to wait user to complete input;
there could be several properties, which fire the same async operation (imagine complex data filter). Some of them should fire operation immediately (e.g. checkbox), some of them need delay before firing;
you need to handle exceptions inside async method and display errors somehow.
P.S. I strongly recommend you to take a look at Reactive UI.

The reason async void is supported is to allow using await in event handlers, which are usually void.
If you want it to be testable, write the entire code in another async Task method and have the event handler call it directly. Test this method in your tests.
void OnPropertyChanged(PropertyChangedEventArgs e)
{
OnPropertyChangedAsync(e)
}
// Test this method
async Task OnPropertyChangedAsync(PropertyChangedEventArgs e)
{
...
}

Little late to the party but I'd say this. First, notice that INotifyPropertyChanged says that your view model will implement
public event PropertyChangedEventHandler? PropertyChanged;
Secondly, if you inspect PropertyChangedEventHandler, you'll see that it's a delegate, of course:
public delegate void PropertyChangedEventHandler(object? sender, PropertyChangedEventArgs e);
So why not implement your own delegate using Func<>? For example, if you're looking to stick with the (object? sender, PropertyChangedEventArgs e) parameter pattern that PropertyChanged uses, then I would implement something like
public Func<object?, PropertyChangedEventArgs, Task>? PropertyChangedAsync { get; set; }
in the same place (or in place of) public event PropertyChangedEventHandler? PropertyChanged;.
From there you can "wire it up" just as you would PropertyChanged:
ViewModel.PropertyChanged += OnViewModelPropertyChanged;
ViewModel.PropertyChangedAsync += OnViewModelPropertyChangedAsync;
private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
// Do something (synchronously) with the notification
}
private Task OnViewModelPropertyChangedAsync(object? sender, PropertyChangedEventArgs e)
{
// Do something (asynchronously) with the notification
return Task.CompletedTask;
}
By the way, if you really want to get fancy, you could also create a custom PropertyChangedEventHandler event with an interface very similar to INotifyPropertyChanged. Obviously, the only difference is you'd want to return Task or Task<T> instead of void. The solution that I mentioned above using Func<object?, PropertyChangedEventArgs, Task> is just a lot more concise (one line).

You can't. INotifyPropertyChanged doesn't support async calls. You need to do a hack, or rethink you strategy.
INotifyPropertyChanged is not intended for async actions. Its goal is to enable a class notify the UI that its data has changed. The UI works in a dedicated thread, so cross-thread operations must be avoided.
You should use the "dreaded" async void approach.
You can also use Dispatcher.BeingInvoke (async () => { … await …} ), but it will be the same as using async void.

Related

Async void on subscribed Prism methods

I understand you should try not to do async void with the exception of event handlers. Does that exception of event handlers include Prism events? Is my example below ok to do?
Module A's View has a DataGrid and when the user clicks a record it publishes the SelectionChangedEvent, the event is subscribed in Module B and might take a while to complete.
public class ModuleA
{
private ObservableCollection<Company> carCollectionOC = new ObservableCollection<Company>();
private void CarCollection_CurrentChanged(object sender, EventArgs e)
{
Company company = (Company)(sender as ICollectionView).CurrentItem;
this.eventAggregator.GetEvent<SelectionChangedEvent>().Publish(company.Brand);
}
}
Module B subscribes and does async void.
public class ModuleB
{
private ObservableCollection<Vehicle> vehicleOC = new ObservableCollection<Vehicle>();
private VehicleService vehicleService;
public ModuleB(IEventAggregator eventAggregator)
{
this.vehicleService = new VehicleService();
this.eventAggregator.GetEvent<SelectionChangedEvent>()
.Subscribe(this.SubscribedMethod,
ThreadOption.UIThread,
false);
}
private async void SubscribedMethod (string brand)
{
this.vehicleOC = await this.GetData(brand);
}
private List<Vehicle> GetVehicles(string carBrand)
{
Console.WriteLine("finishing GetVehicles");
return this.vehicleService.GetVehicleList(carBrand);
}
private async Task<ObservableCollection<Vehicle>> GetData(string carBrand)
{
vehicleListFromService = await Task.Run(() => this.GetVehicles(carBrand));
this.vehicleOC.Clear();
foreach (var vehicle in vehicleListFromService)
this.vehicleOC.Add(vehicle);
return this.vehicleOC;
}
}
Certainly, even stephen clearly (an authority on this subject as far as i am concerned) says:
To summarize this first guideline, you should prefer async Task to
async void. Async Task methods enable easier error-handling,
composability and testability. The exception to this guideline is
asynchronous event handlers, which must return void. This exception
includes methods that are logically event handlers even if they’re not
literally event handlers (for example, ICommand.Execute
implementations).
https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
Personally, I always wrap the contents of an async void method in a try-catch and deal with the exception, regardless of the method's contents. I've written a simple helper class to aid with that.
Does that exception of event handlers include Prism events?
Yes. The subscriber has to be Action, that means void MyHandler() (or async void MyHandler()).

How to implement async INotifyPropertyChanged

I have a class with properties that are bound to my view. To keep my view up-to-date, I implement INotifyPropertyChanged and raise the event everytime some property changes.
Now I got some heavy functions that freeze my application. I want to put them into a background task.
First: here my current approach
(e.g. on button click)
private async void HeavyFunc()
{
foreach (var stuff)
{
count += await Task.Run(() => stuff.Fetch());
}
if (count == 0)
//...
}
stuff class
public async Task<int> Fetch()
{
//network stuff
RaisePropertyChanged("MyProperty");
}
public async void RaisePropertyChanged(string pChangedProperty)
{
await Application.Current.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
new ThreadStart(() =>
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty);
}
);
}
The code above gives an exception ("DependencySource" must be created in the same thread like "DependencyObject").
AFAIK, you generally need to create a new thread and run it (while awaiting it). ´await Task.Run(...);´ should do this job.
Since the PropertyChanged event directly influences the UI, calling it in the UI thread seems to be a good decision. This is why I call Dispatcher.BeginInvoke.
What I don't understand: the exception above is caused when different threads are responsible for the data. But I explicitely calling the event on my UI-thread and the object should be created by the UI-thread too. So why do I get an exception?
My main question is: How do I implement the events for the INotifyPropertyChanged interface generally to avoid or handle most of the async programming problems like above? What should be considered while constructing the functions?
Now I got some heavy functions that freeze my application.
If you're really doing asynchronous "network stuff", then it shouldn't be freezing the app.
My main question is: How do I implement the events for the INotifyPropertyChanged interface generally to avoid or handle most of the async programming problems like above?
The approach that I prefer is to not handle this in the event raising code. Instead, structure the rest of your code so that it respects the UI layer.
In other words, divide your "service" (or "business logic") code from your "UI" code so that it works like this:
// In StuffService class:
public async Task<Result> FetchAsync()
{
//network stuff
return result;
}
// In StuffViewModel class:
public async void ButtonClicked()
{
foreach (var stuff)
{
var result = await Task.Run(() => _stuffService.FetchAsync());
MyProperty = result.MyProperty;
count += result.Count;
}
if (count == 0)
//...
}
public Property MyProperty
{
get { return _myProperty; }
set
{
_myProperty = value;
RaisePropertyChanged();
}
}
private void RaisePropertyChanged([CallerMemberName] string pChangedProperty = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty));
}
This way, there's no manual thread jumping, all properties have the standard ViewModel implementation, the code is simpler and more maintainable, etc.
I did leave in the call to Task.Run, although this should be superfluous if your network calls are truly asynchronous.

C# Call a showdialog inside backgroundworker from a Class library [duplicate]

I am working on a VS project/solution that is used by different applications. My job is to refactor the project and change it from using xxxAsync method to using BeginInvoke.
I came up to something similar to the following code:
public class AsyncTestModel {
private delegate string DoTaskDelegate();
public static EventHandler<TaskCompletedEventArgs> OnTaskCompleted;
public static void InvokeTask() {
DoTaskDelegate taskDelegate = Task;
taskDelegate.BeginInvoke(new AsyncCallback(TaskCallback), null);
}
private static string Task() {
Thread.Sleep(5000);
return "Thread Task successfully completed.";
}
private static void TaskCallback(IAsyncResult ar) {
string result = ((DoTaskDelegate)((System.Runtime.Remoting.Messaging.AsyncResult)ar).AsyncDelegate).EndInvoke(ar);
if (OnTaskCompleted != null) {
OnTaskCompleted(null, new TaskCompletedEventArgs(result));
}
}
}
public class TaskCompletedEventArgs : EventArgs {
private string _message;
public TaskCompletedEventArgs(string message) : base() {
_message = message;
}
public string Message {
get {
return _message;
}
}
}
I've tested this on a new UI project I've created. The UI project contains a button and a label controls. The UI has the following code:
private void button1_Click(object sender, EventArgs e) {
AsyncTestModel.OnTaskCompleted += OnTaskCompleted;
AsyncTestModel.InvokeTask();
}
private void OnTaskCompleted(object sender, TaskCompletedEventArgs e) {
UpdateLabel(e.Message);
}
private void UpdateLabel(string message) {
this.label1.Text = message;
}
After running this, I've encountered the cross-thread exception saying the the control 'label1' is being accessed from other thread aside the thread that it was created.
Is there a way for me to invoke the OnTaskCompleted event handler on the same thread that calls the BeginInvoke method? I know I could just use the form's InvokeRequired and call the form's BeginInvoke like the following:
private delegate void DoUpdateLabelDelegate(string message);
private void UpdateLabel(string message) {
if (this.InvokeRequired) {
IAsyncResult ar = this.BeginInvoke(new DoUpdateLabelDelegate(UpdateLabel), message);
this.EndInvoke(ar);
return;
}
this.label1.Text = message;
}
But the solution above will require me to ask and apply that solution to the other development team handling applications that uses my project/solution. Those other developers shouldn't be required to know that the methods hooked to the event handler are running from different thread.
Thanks, in advance.
As designed, no, you have absolutely no idea which thread is the one on which the client's UI runs.
You can arbitrarily demand that your InvokeTask() is to be called from that UI thread. Now you know, you can copy SynchronizationContext.Current in the InvokeTask() method and, later, call its Post() or Send() method to call a method that fires the event. This is the pattern used by, for example, BackgroundWorker and async/await. Do note that copying the Current property is required to make this work, don't skip it.
That of course still won't work when your InvokeTask() method is not called from the UI thread, you'll see that Synchronization.Current is null and have no hope to marshal the call. If that's a concern then you could expose a property of type ISynchronizeInvoke, call it SynchronizingObject. Now it is up to the client code to make the call, they'll have no trouble setting the property, they'll simply assign this in their form class constructor. And you use the property's Post or Send method to call the method that raises the event. This is the pattern used by for example the Process and FileSystemWatcher classes. Don't use it if you expect your library to be used by non-Winforms client apps, unfortunately later GUI libraries like WPF and Silverlight don't implement the interface. Otherwise the exact same problem with approaches like calling Control.Begin/Invoke() yourself.
try to use this, maybe it can help you.
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
//Do something...
});

async/await in MVVM without Void methods

I want to use async/await on my windows phone 8 MVVM project and I'm struggling to find a good way to implement my ICommands using this api.
I've been reading a few articles about the subject and I bumped into this one from MSDN below, which states that I have to avoid async voids since it gets difficult to catch unhandled exceptions:
http://msdn.microsoft.com/en-us/magazine/jj991977.aspx
In another question I asked about the subject, someone also said that I shouldn't use async voids. Unless with events.
But the problem is that all examples I can find on the internet use async voids.
This two articles I found are examples:
http://richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/ and
http://blog.mycupof.net/2012/08/23/mvvm-asyncdelegatecommand-what-asyncawait-can-do-for-uidevelopment/
The last one is an implementation of ICommand using async/await, but it also uses async voids.
I'm trying to come up with a solution for this, so I wrote this implementation of ICommand based on the RelayCommand:
public delegate Task AsyncAction();
public class RelayCommandAsync : ICommand
{
private AsyncAction _handler;
public RelayCommandAsync(AsyncAction handler)
{
_handler = handler;
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
if (value != _isEnabled)
{
_isEnabled = value;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
ExecuteAsync();
}
private Task ExecuteAsync()
{
return _handler();
}
}
And I'm trying to use it like this:
in the constructor:
saveCommand = new RelayCommandAsync(SaveSourceAsync);
then:
private async Task SaveSourceAsync()
{
await Task.Run(() => { Save(); });
}
private void Save()
{
// Slow operation
}
The problem is that I'm not feeling comfortable with this and any other implementation as I don't know which is the best and optimal.
Can anyone give some light on how I should use it, preferably with MVVM?
In the referenced article, I did point out that ICommand.Execute is practically an event handler, so it would be considered an exception from the "avoid async void" guideline:
To summarize this first guideline, you should prefer async Task to async void... The exception to this guideline is asynchronous event handlers, which must return void. This exception includes methods that are logically event handlers even if they’re not literally event handlers (for example, ICommand.Execute implementations).
Regarding your ICommand implementation, it actually introduces a flaw by not using async void: the ICommand.Execute implementation will discard the Task without observing its exceptions. So that implementation will ignore any exceptions raised by the async delegate.
In contrast, the blog post you linked to has an async void ICommand.Execute which awaits the Task, allowing the exception to propagate to the UI synchronization context. Which - in this case - is the desired behavior because it's the same behavior you get when a synchronous ICommand.Execute raises an exception.
If you have the inclination, I'd like you to try out an ICommand or two that I've written for possible future inclusion in my AsyncEx library. The first one is a simple command very similar to the one in the blog you posted. The second one is a much more complete "asynchronous command" implementation including cancellation, progress reporting, and automatic management of CanExecute. I'd appreciate any feedback.

callbacks in c#, calling order and return

A simple question on callbacks. Do callback functions return to the next line in the calling function after completion ?
class A
{
public delegate void A();
public event A onA;
public void func()
{
//some code 1
onA();
//some code 2
}
So the question is will onA event go and execute the respective handler and then come back to 'some code 2' bit or is this asynchronous and code will not wait for the event to be fully handled?
I hope the question is clear.
Thanks
}
The way you used delegate: is synchronous. If you want asynchronous you must invoke delegate with: BeginInvoke method.
Yes, in your example onA() will trigger all over the event handlers hooked up to A to fire. They are just methods that will be called. After they are all called, control will return to func().
It is not asynchronous - you are only using one thread. Everything will happen in a well defined order.
A good way to experiment would be to step through the code in your example using the built in debugger.
Your code isn't assync. But you can Use Delegates Asynchronously.
No, calling a event isn't a assync thing. Your code func() will only continue after onA() ends running.
You would use BeginInvoke or Threading if will wants assync code running.
Read more about delegate invokes here.
As others have pointed out, this is entirely synchronous. If you wanted to execute this asynchronously you would have to write this differently.
Additionally, if the event 'onA' is not subscribed to, onA() will raise a null reference exception.
The usual pattern is to define an event 'Foo' and a method 'OnFoo' which you call when the event occurs. From the name of the event I suspect this is what you desire - e.g.:-
class Foo // Class and member names must be distinct
{
public delegate void ADelegate();
public event ADelegate A;
private void OnA()
{
if(A != null)
A();
}
public void Func()
{
// Some code...
OnA();
// More code...
}
}
If you want to call the subscribed event handlers asynchronously you can use BeginInvoke() and EndInvoke() thus:-
class Foo // Class and member names must be distinct
{
public delegate void ADelegate();
public event ADelegate A;
private void OnA()
{
if (A == null) return;
// There may be multiple subscribers, invoke each separately.
foreach(ADelegate del in A.GetInvocationList())
del.BeginInvoke(SubscriberCallback, del);
}
private void SubscriberCallback(IAsyncResult result)
{
var del = (ADelegate) result.AsyncState;
del.EndInvoke(result);
// Do something in the callback...
}
public void Func()
{
// Some code...
OnA();
// More code...
}
}
Note that this code won't wait to finish executing the event subscriber(s), you would have to thread the async result through the event call to ensure this happens.
Note that the 'callback' is the method you specify in the asynchronous BeginInvoke (since it is 'called back' once the async work is done), and doesn't return to Func() as it is executed in a separate thread.

Categories