Reputation: 719
Let's suppose I have a long running Web API call (async method) which returns a string.
Is there a best practice between those 2 solutions to display the result in a WPF property without blocking UI ? Or is there another one ?
Note: both solutions are not freezing UI and I already view posts How to call an async method from a getter or setter? and Async property in c#.
private async Task<string> GetAsyncProperty()
{
string result = "Async Property Value";
// Web api call...
await Task.Delay(TimeSpan.FromSeconds(10));
return result;
}
XAML:
<TextBlock Text="{Binding Path=AsyncPropertyA, UpdateSourceTrigger=PropertyChanged}" />
ViewModel:
public MyConstructor()
{
Task task = SetAsyncPropertyA();
}
private async Task SetAsyncPropertyA()
{
this.AsyncPropertyA = await GetAsyncProperty().ConfigureAwait(false);
}
XAML:
<TextBlock Text="{Binding Path=AsyncPropertyB, UpdateSourceTrigger=PropertyChanged, IsAsync=True, FallbackValue='Loading B...'}" />
ViewModel:
public string AsyncPropertyB
{
get
{
return GetAsyncPropertyB();
}
}
private string GetAsyncPropertyB()
{
return Task.Run(() => GetAsyncProperty()).Result;
}
Note: in solution B, I can add FallbackValue that's not working in solution A and potentially some other UI updates in ContinueWith of the Task.Run.
Upvotes: 1
Views: 12270
Reputation: 2686
In both cases, you're not catching any errors that might happen while trying to call the Web API. You might want to log it to a file and/or show an error message to the user.
In that case, await makes it easy - you can just use try/catch:
public MyConstructor()
{
try
{
Task task = SetAsyncPropertyA();
}
catch (Exception e)
{
// log the error or show a message
}
}
private async Task SetAsyncPropertyA()
{
this.AsyncPropertyA = await GetAsyncProperty().ConfigureAwait(false);
}
You could also move the try/catch to the async method. In that case, since there's no chance of an error escaping from it, you could make it async void. Sometimes this is necessary for event handlers (at least in Windows Forms - not sure about WPF.)
public MyConstructor()
{
SetAsyncPropertyA();
}
private async void SetAsyncPropertyA()
{
try
{
this.AsyncPropertyA = await GetAsyncProperty().ConfigureAwait(false);
}
catch (Exception e)
{
// log the error or show a message
}
}
Upvotes: 2
Reputation: 2936
You should try to use a good framework for that, which already inveted that wheel.
Take a look at ReactiveUI command sample:
LoadTweetsCommand = ReactiveCommand.CreateAsyncTask(() => LoadTweets())
LoadTweetsCommand.ToProperty(this, x => x.TheTweets, out theTweets);
LoadTweetsCommand.ThrownExceptions.Subscribe(ex => /* handle exception here */);
Those extensions work on IObservable, which on itself is very powerfull tool:
Observable.FromAsync(async () =>
{
await Task.Delay(100);
return 5;
}).ToProperty(x => )
Upvotes: 2