MVVM c# how to load async data into a property? - c#

I wonder if there's a better approach to load async data into a property. now I create an async function and raise a Task in the Get part of the property like this:
private ObservableCollection<CProyecto> prope;
public ObservableCollection<CProyecto> Prope
{
get
{
if (prope == null)
{
Task.Run(()=> LoadData()).Wait();
}
return proyectos;
}
set
{
prope = value;
RaisePropertyChanged();
}
}
async private Task LoadData()
{
Prope = await clsStaticClassDataLoader.GetDataFromWebService();
}
This approach works, but I don't like the use of .Wait, because that can freeze the screen if the service doesn´t respond fast.
Can you please guide me on this matter?
thanks in advance

The way I handled this was to start the process of loading the property when the object was constructed, but I did not await the result. Since the property notifies when it is populated, the bindings worked just fine. Essentially it works like this:
public class MyClass : INotifyPropertyChanged
{
private ObservableCollection<CProyecto> prope;
public ObservableCollection<CProyecto> Prope
{
get { return prope; }
set { prope = value; RaisePropertyChanged(nameof(Prope)); }
}
public MyClass()
{
// Don't wait or await. When it's ready
// the UI will get notified.
LoadData();
}
async private Task LoadData()
{
Prope = await clsStaticClassDataLoader.GetDataFromWebService();
}
}
This works very well, and does not cause any delays or stuttering in the UI. If you want the collection to never be null (a good practice IMO), you can pre-initialize the prope field with an empty collection.

I suggest you read my MSDN article on async MVVM data-binding. I have a library (github link) that provides a NotifyTask<T> type, which can be used as such:
public class MyClass : INotifyPropertyChanged
{
public NotifyTask<ObservableCollection<CProyecto>> Prope { get; private set; }
public MyClass()
{
// Synchronously *start* the operation.
Prope = NotifyTask.Create(LoadDataAsync());
}
async private Task<ObservableCollection<CProyecto>> LoadDataAsync()
{
return await clsStaticClassDataLoader.GetDataFromWebService();
}
}
Then your databinding would operate on Prope.Result.
The advantage of this approach is that you can also use databinding to hide/show busy indicators (Prope.IsNotCompleted), show controls when the data is available (Prope.IsSuccessfullyCompleted), and error notifications (Prope.IsFaulted / Prope.ErrorMessage).
Also, you can specify a non-null default value, if you wish:
Prope = NotifyTask.Create(LoadDataAsync(), new ObservableCollection<CProyecto>());

Your current implementation of the Prope property doesn't make much sense. It is pointless to execute the LoadData method on a background thread since you block the main thread anyway when you call Wait(). You might as well call Wait() directly on the task returned by the LoadData() method:
//BAD IMPLEMENTATION!
private ObservableCollection<CProyecto> prope;
public ObservableCollection<CProyecto> Prope
{
get
{
if (prope == null)
LoadData().Wait();
return proyectos;
}
set { prope = value; RaisePropertyChanged(); }
}
The above implementation is still a bad one. The getter of a property is not supposed to perform an asynchronous operation. You should read #Stephen Cleary's blog post on the subject: https://blog.stephencleary.com/2013/01/async-oop-3-properties.html
...and look into his NotifyTaskCompletion type in his AsyncEx library: https://github.com/StephenCleary/AsyncEx

Related

Using Mediator to call async method from within a data-bound property setter

I need to call an async method ConnectToLibrary once a book is selected, meaning once SelectedBook property is set. I saw many solutions. But all of them require hacks or starting a task/thread from a setter. My question, what's wrong with using a mediator like Messenger from Microsoft Toolkit.Mvvm?
I can just register a callback to ConnectToLibrary with Messenger.Register<...BookSelectedMessage>(...ConnectToLibrary...) and then call Messenger.Send(new BookSelectedMessage()) from the SelectedBook's setter.
Is this the correct way to do this in MVVM?
public MyViewModel : ObservableRecipient
{
public ObservableCollection<BookInfo> Books { get; } = new();
private BookInfo _selectedBook;
public BookInfo SelectedBook
{
get => _selectedBook;
set => SetProperty(ref _selectedBook, value);
}
private async Task ConnectToLibrary(BookInfo info)
{
await START_SOME_ASYNC_METHOD();
}
}
Nothing. In either case any Exception is swallowed. And since you are asking, what's wrong with starting a thread from a Setter? It sounds to me like the requirements of your app require this anyway, no?

Kick off async method in constructor in c#

I'm wondering is it safe to call async method in a constructor in the following way:
Let's say we have an async method Refresh that is fetching data from the internet. We are also using Reactive Extensions to notify everyone that is interested that new data was fetched.
I'm wondering is it safe to call Refresh first time in a class constructor? Can I use such construction?
Task.Run(Refresh);
or
Refresh().ConfigureAwait(false)
I'm not really interested here if the method has finished or not, since I will get notified through Reactive Extensions when data is fetched.
Is it ok to do something like this?
public class MyClass
{
BehvaiorSubject<Data> _dataObservable = new BehvaiorSubject(Data.Default);
IObservable DataObservable => _dataObservable;
public MyClass()
{
Refresh().ConfigureAwait(false);
}
public async Task Refresh()
{
try
{
var data = await FetchDataFromNetwork();
_dataObservable.OnNext(data);
}
catch (VariousExceptions e)
{
//do some appropriate stuff
}
catch(Exception)
{
//do some appropriate stuff
}
}
}
Though people are against the idea, we have similar things in our project :)
The thing is you have to properly handle any exceptions thrown from that Task in case they go unobserved. Also you might need to expose the task via either a method or a property, just so that it is possible to await (when necessary) the async part is finished.
class MyClass
{
public MyClass()
{
InitTask = Task.Delay(3000);
// Handle task exception.
InitTask.ContinueWith(task => task.Exception, TaskContinuationOptions.OnlyOnFaulted);
}
public Task InitTask { get; }
}

Do I need Task.Run to call an async method from a constructor? [duplicate]

I have a project where I'm trying to populate some data in a constructor:
public class ViewModel
{
public ObservableCollection<TData> Data { get; set; }
async public ViewModel()
{
Data = await GetDataTask();
}
public Task<ObservableCollection<TData>> GetDataTask()
{
Task<ObservableCollection<TData>> task;
//Create a task which represents getting the data
return task;
}
}
Unfortunately, I'm getting an error:
The modifier async is not valid for this item
Of course, if I wrap in a standard method and call that from the constructor:
public async void Foo()
{
Data = await GetDataTask();
}
it works fine. Likewise, if I use the old inside-out way
GetData().ContinueWith(t => Data = t.Result);
That works too. I was just wondering why we can't call await from within a constructor directly. There are probably lots of (even obvious) edge cases and reasons against it, I just can't think of any. I've also search around for an explanation, but can't seem to find any.
Since it is not possible to make an async constructor, I use a static async method that returns a class instance created by a private constructor. This is not elegant but it works ok.
public class ViewModel
{
public ObservableCollection<TData> Data { get; set; }
//static async method that behave like a constructor
async public static Task<ViewModel> BuildViewModelAsync()
{
ObservableCollection<TData> tmpData = await GetDataTask();
return new ViewModel(tmpData);
}
// private constructor called by the async method
private ViewModel(ObservableCollection<TData> Data)
{
this.Data = Data;
}
}
Constructor acts very similarly to a method returning the constructed type. And async method can't return just any type, it has to be either “fire and forget” void, or Task.
If the constructor of type T actually returned Task<T>, that would be very confusing, I think.
If the async constructor behaved the same way as an async void method, that kind of breaks what constructor is meant to be. After constructor returns, you should get a fully initialized object. Not an object that will be actually properly initialized at some undefined point in the future. That is, if you're lucky and the async initialization doesn't fail.
All this is just a guess. But it seems to me that having the possibility of an async constructor brings more trouble than it's worth.
If you actually want the “fire and forget” semantics of async void methods (which should be avoided, if possible), you can easily encapsulate all the code in an async void method and call that from your constructor, as you mentioned in the question.
Your problem is comparable to the creation of a file object and opening the file. In fact there are a lot of classes where you have to perform two steps before you can actually use the object: create + Initialize (often called something similar to Open).
The advantage of this is that the constructor can be lightweight. If desired, you can change some properties before actually initializing the object. When all properties are set, the Initialize/Open function is called to prepare the object to be used. This Initialize function can be async.
The disadvantage is that you have to trust the user of your class that he will call Initialize() before he uses any other function of your class. In fact if you want to make your class full proof (fool proof?) you have to check in every function that the Initialize() has been called.
The pattern to make this easier is to declare the constructor private and make a public static function that will construct the object and call Initialize() before returning the constructed object. This way you'll know that everyone who has access to the object has used the Initialize function.
The example shows a class that mimics your desired async constructor
public MyClass
{
public static async Task<MyClass> CreateAsync(...)
{
MyClass x = new MyClass();
await x.InitializeAsync(...)
return x;
}
// make sure no one but the Create function can call the constructor:
private MyClass(){}
private async Task InitializeAsync(...)
{
// do the async things you wanted to do in your async constructor
}
public async Task<int> OtherFunctionAsync(int a, int b)
{
return await ... // return something useful
}
Usage will be as follows:
public async Task<int> SomethingAsync()
{
// Create and initialize a MyClass object
MyClass myObject = await MyClass.CreateAsync(...);
// use the created object:
return await myObject.OtherFunctionAsync(4, 7);
}
if you make constructor asynchronous, after creating an object, you may fall into problems like null values instead of instance objects. For instance;
MyClass instance = new MyClass();
instance.Foo(); // null exception here
That's why they don't allow this i guess.
In this particular case, a viewModel is required to launch the task and notify the view upon its completion. An "async property", not an "async constructor", is in order.
I just released AsyncMVVM, which solves exactly this problem (among others). Should you use it, your ViewModel would become:
public class ViewModel : AsyncBindableBase
{
public ObservableCollection<TData> Data
{
get { return Property.Get(GetDataAsync); }
}
private Task<ObservableCollection<TData>> GetDataAsync()
{
//Get the data asynchronously
}
}
Strangely enough, Silverlight is supported. :)
I was just wondering why we can't call await from within a constructor directly.
I believe the short answer is simply: Because the .Net team has not programmed this feature.
I believe with the right syntax this could be implemented and shouldn't be too confusing or error prone. I think Stephen Cleary's blog post and several other answers here have implicitly pointed out that there is no fundamental reason against it, and more than that - solved that lack with workarounds. The existence of these relatively simple workarounds is probably one of the reasons why this feature has not (yet) been implemented.
calling async in constructor maybe cause deadlock, please refer to
http://social.msdn.microsoft.com/Forums/en/winappswithcsharp/thread/0d24419e-36ad-4157-abb5-3d9e6c5dacf1
http://blogs.msdn.com/b/pfxteam/archive/2011/01/13/10115163.aspx
Some of the answers involve creating a new public method. Without doing this, use the Lazy<T> class:
public class ViewModel
{
private Lazy<ObservableCollection<TData>> Data;
async public ViewModel()
{
Data = new Lazy<ObservableCollection<TData>>(GetDataTask);
}
public ObservableCollection<TData> GetDataTask()
{
Task<ObservableCollection<TData>> task;
//Create a task which represents getting the data
return task.GetAwaiter().GetResult();
}
}
To use Data, use Data.Value.
C# doesn't allow async constructors. Constructors are meant to return fast after some brief initialization. You don't expect and you don't want to wait for an instance i.e. the constructor to return. Therefore, even if async constructors were possible, a constructor is not a place for long-running operations or starting background threads. The only purpose of a constructor is initialization of instance or class members to a default value or the captured constructor parameters. You always create the instance and then call DoSomething() on this instance. Async operations are no exception. You always defer expensive initialization of members.
There are a few solutions to avoid the requirement of async constructors.
A simple alternative solution using Lazy<T> or AsyncLazy<T> (requires to install the Microsoft.VisualStudio.Threading package via the NuGet Package Manager). Lazy<T> allows to defer the instantiation or allocation of expensive resources.
public class OrderService
{
public List<object> Orders => this.OrdersInitializer.GetValue();
private AsyncLazy<List<object>> OrdersInitializer { get; }
public OrderService()
=> this.OrdersInitializer = new AsyncLazy<List<object>>(InitializeOrdersAsync, new JoinableTaskFactory(new JoinableTaskContext()));
private async Task<List<object>> InitializeOrdersAsync()
{
await Task.Delay(TimeSpan.FromSeconds(5));
return new List<object> { 1, 2, 3 };
}
}
public static void Main()
{
var orderService = new OrderService();
// Trigger async initialization
orderService.Orders.Add(4);
}
You can expose the data using a method instead of a property
public class OrderService
{
private List<object> Orders { get; set; }
public async Task<List<object>> GetOrdersAsync()
{
if (this.Orders == null)
{
await Task.Delay(TimeSpan.FromSeconds(5));
this.Orders = new List<object> { 1, 2, 3 };
}
return this.Orders;
}
}
public static async Task Main()
{
var orderService = new OrderService();
// Trigger async initialization
List<object> orders = await orderService.GetOrdersAsync();
}
Use an InitializeAsync method that must be called before using the instance
public class OrderService
{
private List<object> orders;
public List<object> Orders
{
get
{
if (!this.IsInitialized)
{
throw new InvalidOperationException();
}
return this.orders;
}
private set
{
this.orders = value;
}
}
public bool IsInitialized { get; private set; }
public async Task<List<object>> InitializeAsync()
{
if (this.IsInitialized)
{
return;
}
await Task.Delay(TimeSpan.FromSeconds(5));
this.Orders = new List<object> { 1, 2, 3 };
this.IsInitialized = true;
}
}
public static async Task Main()
{
var orderService = new OrderService();
// Trigger async initialization
await orderService.InitializeAsync();
}
Instantiate the instance by passing the expensive arguments to the constructor
public class OrderService
{
public List<object> Orders { get; }
public async Task<List<object>> OrderService(List<object> orders)
=> this.Orders = orders;
}
public static async Task Main()
{
List<object> orders = await GetOrdersAsync();
// Instantiate with the result of the async operation
var orderService = new OrderService(orders);
}
private static async Task<List<object>> GetOrdersAsync()
{
await Task.Delay(TimeSpan.FromSeconds(5));
return new List<object> { 1, 2, 3 };
}
Use a factory method and a private constructor
public class OrderService
{
public List<object> Orders { get; set; }
private OrderServiceBase()
=> this.Orders = new List<object>();
public static async Task<OrderService> CreateInstanceAsync()
{
var instance = new OrderService();
await Task.Delay(TimeSpan.FromSeconds(5));
instance.Orders = new List<object> { 1, 2, 3 };
return instance;
}
}
public static async Task Main()
{
// Trigger async initialization
OrderService orderService = await OrderService.CreateInstanceAsync();
}
you can use Action inside Constructor
public class ViewModel
{
public ObservableCollection<TData> Data { get; set; }
public ViewModel()
{
new Action(async () =>
{
Data = await GetDataTask();
}).Invoke();
}
public Task<ObservableCollection<TData>> GetDataTask()
{
Task<ObservableCollection<TData>> task;
//Create a task which represents getting the data
return task;
}
}
you can create a wrapper and inject a functor representing the constructor:
class AsyncConstruct<T>
where T: class
{
private readonly Task<T> m_construction;
private T m_constructed;
public AsyncConstruct(Func<T> createFunc)
{
m_constructed = null;
m_construction = Task.Run(()=>createFunc());
}
public T Get()
{
if(m_constructed == null)
{
m_constructed = m_construction.Result;
}
return m_constructed;
}
}
Please bump this language request:
https://github.com/dotnet/csharplang/discussions/419
The amount of boilerplate code everyone needs to write to have a fully initialized async object is crazy and completely opposite of the trend in C# (less boilerplate).
I would use something like this.
public class MyViewModel
{
public MyDataTable Data { get; set; }
public MyViewModel()
{
loadData(() => GetData());
}
private async void loadData(Func<DataTable> load)
{
try
{
MyDataTable = await Task.Run(load);
}
catch (Exception ex)
{
//log
}
}
private DataTable GetData()
{
DataTable data;
// get data and return
return data;
}
}
This is as close to I can get for constructors.
I use this easy trick.
public sealed partial class NamePage
{
private readonly Task _initializingTask;
public NamePage()
{
_initializingTask = Init();
}
private async Task Init()
{
/*
Initialization that you need with await/async stuff allowed
*/
}
}
I'm not familiar with the async keyword (is this specific to Silverlight or a new feature in the beta version of Visual Studio?), but I think I can give you an idea of why you can't do this.
If I do:
var o = new MyObject();
MessageBox(o.SomeProperty.ToString());
o may not be done initializing before the next line of code runs. An instantiation of your object cannot be assigned until your constructor is completed, and making the constructor asynchronous wouldn't change that so what would be the point? However, you could call an asynchronous method from your constructor and then your constructor could complete and you would get your instantiation while the async method is still doing whatever it needs to do to setup your object.

Run long operation when Property Changed

How can I run some long operation, when my property raises PropertyChanged event?
Example:
class SomeClass : INotifyPropertyChanged
{
public ObservableConllection<Item> Items { get; set; }
public string Path
{
get => _path;
if (_path != value) {
_path = value;
OnPropertyChanged(nameof(Path));
// await Task.Run(()=> long operation, for example load some Items use "_path");
}
}
Property can't be async and I think it is "normal". But what should I do?
I think that such a case occurs often.
You should read Stephen Cleary's MSDN article about asynchronous data-bound properties where he defines a "task watcher" class called NotifyTaskCompletion<T> that implements the INotifyPropertyChanged interface and has a Result property that you can bind to:
Async Programming : Patterns for Asynchronous MVVM Applications: Data Binding: https://msdn.microsoft.com/en-us/magazine/dn605875.aspx
public class MainViewModel : INotifyPropertyChanged
{
public string Path
{
get { return _path; }
set
{
if (_path != value)
{
_path = value;
OnPropertyChanged(nameof(Path));
AsyncProperty = new NotifyTaskCompletion<int>(YourAsyncMethod());
}
}
}
public NotifyTaskCompletion<string> AsyncProperty { get; private set; }
}
<Label Content="{Binding AsyncProperty.Result}"/>
You can use Task.Run without await. It may or may not work well depending on the case, there is no universal answer regarding that.
You can create a method like this to set the value, it is a more sure way to do this. However if you need a databinding this can't work:
public async Task SetPath(string value)
{
if (_path != value) {
_path = value;
OnPropertyChanged(nameof(Path));
await Task.Run(()=> ...);
}
If you need data binding and want to use await, then it is usually the best practice to use debouncing with Timer - you don't want some expensive operation to be available without restriction to the user so that he can freeze or crash the app.

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.

Categories