Aug 16, 2012 at 9:04 PM
Edited Aug 16, 2012 at 9:05 PM
|
From the documentation I've realized that I can use Caliburn Micro's coroutines for async operations. Out of the box and without extra technologies. So I've implemented the next code:
public class SimpleViewModel : Screen
{
// ...
protected override void OnViewLoaded(object view)
{
base.OnViewLoaded(view);
Coroutine.BeginExecute(RunTask());
}
public IEnumerator<IResult> RunTask()
{
yield return new SimpleTask();
}
// ...
}
SimpleTask:
public class SimpleTask : IResult
{
public void Execute(ActionExecutionContext context)
{
Thread.Sleep(10000);
}
public event EventHandler<ResultCompletionEventArgs> Completed;
}
I've hoped that code in Execute method will run async. But this not happen. My UI-thread was blocked for 10 seconds.
Where I made a mistake? Or my assumption about async nature of coroutines was wrong?
|
|
Aug 17, 2012 at 7:48 AM
Edited Aug 17, 2012 at 7:50 AM
|
Caliburn.Micro Coroutines help you to execute async routines in a synchronous way. Not the other way around. Regarding your problem: Out of the box CM gives you the possibilities to find a solution quite fast... ;-)
To accomplish what you'd like to do, I'd recommend you to take a look at the .NET BackgroundWorker and create a coroutine (IResult) around it. Something like this:
public class BackgroundWork : IResult
{
private readonly Action _work;
private readonly Action _onSuccess;
private readonly Action<Exception> _onFail;
public BackgroundWork(Action work, Action onSuccess, Action<Exception> onFail)
{
_work = work;
_onSuccess = onSuccess;
_onFail = onFail;
}
#region Implementation of IResult
public void Execute(ActionExecutionContext context)
{
Exception error = null;
var worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
try
{
_work();
}
catch (Exception ex)
{
error = ex;
}
};
worker.RunWorkerCompleted += (s, e) =>
{
if (error == null && _onSuccess != null)
_onSuccess.OnUIThread();
if (error != null && _onFail != null)
{
Caliburn.Micro.Execute.OnUIThread(() => _onFail(error));
}
Completed(this, new ResultCompletionEventArgs { Error = error });
};
worker.RunWorkerAsync();
}
public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
#endregion
}
Now you can call this in your ViewModel like this:
public IEnumerator RunTask()
{
yield return new BackgroundWork(() => Thread.Sleep(1000), () => AnswerText = "Wohoo, Completed!", err => AnswerText = err.Message);
}
Just a hint, because I notced this in your coroutine: If you don't throw the Completed event in an IResult, the coroutine won't finish. So make sure you call Completed(this, new ResultCompletionEventArgs()), when the coroutine is finished!
Roland
|
|