问题
As mentioned elsewhere, the new .NET async/await model propagates through layers of software like a virus. A recent async change has now bubbled up to my view model, and I am wondering if it is safe change declaration from public void DoStuff()
to public async Task DoStuff()
?
Thanks!
回答1:
The support of asynchronous programming model in Caliburn.Micro is pretty good now.
Few things you can do:
- Use async/await in Action method. Be careful, as action methods are technically event handlers, you shoud do
async void
rather thanasync Task
. - Asynchronous event handlers for Screen's events, like Activated, ViewLoaded and other.
- Asynchronous overrides for Screen's methods: OnInitialize, OnActivate, ... You can override then as
protected override async void OnInitialize(){}
and inside you can await another task. - Convert Coroutines to Tasks. Use
ExecuteAsync()
extension method. Coroutines still have some advantages in some scenarios, like execution context. IHandleWithTask<TMessage>
- pretty handy...
There's a blog post desribing some use cases with few code snippets. And a GitHub repository with sample project I've used to play with async/await in Caliburn.
回答2:
The answer is 'yes', starting with Caliburn.Micro 1.5.
See release announcement.
回答3:
Marco Amendola, a project manager in the Caliburn.Micro project wrote an article that has this title: Coroutines are dead. Long live Coroutines. and he titled it this way because of the emergence of the async/wait programming model and if you read the article you will see that async/wait bring to life what Coroutines did in the past so i assume you could use them safely where you have used Coroutines before. i advise you to read the article.
回答4:
It's safe, but will break your existing global exception handling. After I did the refactoring, I didn't see any error dialogues anymore, to fix that, I had to subscribe to the Coroutine.Completed
event:
Coroutine.Completed += (s, a) =>
{
//Do something here ...
};
You can do that in your App.xaml.cs
file.
Example from my code on how I handle all possible errors raised in my app:
protected override void OnStartup(StartupEventArgs e)
{
SetupExceptionHandlers();
base.OnStartup(e);
}
private void SetupExceptionHandlers()
{
AppDomain.CurrentDomain.UnhandledException += (s, a) =>
{
HandleException((Exception)a.ExceptionObject, "AppDomain.CurrentDomain.UnhandledException");
};
Current.DispatcherUnhandledException += (s, a) =>
{
HandleException(a.Exception, "Application.Current.DispatcherUnhandledException");
a.Handled = true;
};
TaskScheduler.UnobservedTaskException += (s, a) =>
{
HandleException(a.Exception, "TaskScheduler.UnobservedTaskException");
a.SetObserved();
};
Coroutine.Completed += (s, a) =>
{
if (a.Error != null)
{
HandleException(a.Error, "Coroutine.Completed");
}
};
}
private void HandleException(Exception exception, string source)
{
logger.Error(exception, "Unhandled exception occured (Source: {0})", source);
var msg = new ShowErrorDialogEvent(exception, exception.GetBaseException().Message);
eventAggregator.PublishOnUIThread(msg);
}
In-case you're wondering, the logger
and eventAggregator
variables are instantiated from the bootstrapper class in the OnStartup
method before calling DisplayRootViewFor
.
来源:https://stackoverflow.com/questions/15417354/will-caliburn-micro-do-the-right-thing-with-async-method-on-viewmodel