从文档中我意识到我可以使用Caliburn Micro的协同程序进行异步操作。开箱即用,没有额外的技术。所以我在Windows Phone应用程序中实现了下一个代码:
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;
}
我希望Execute方法中的代码将运行异步。但这不会发生。我的UI线程被阻止了10秒钟。
我犯了哪个错误?或者我对协同程序的异步性质的假设是错误的?
答案 0 :(得分:12)
我花了一整天的时间搜索和尝试代码示例,最终得到了一些有效的东西(即使用不阻止UI的Caliburn协程的异步操作),所以我允许自己分享它。
据我所知,Caliburn中的Coroutines不处理线程,它们只是提供了一种优雅的方法来在一个方法中处理异步执行和控制代码。必须使用其他工具(如BackgroundWorkers)来处理后台线程中的操作。
我发现this link非常有趣,因为银光。目的是将后台工作者包含在一个包含协程调用的类中。
正如我在WPF中想要的那样略有不同,我最终得到了可在我的机器上运行的代码示例:
包装课程:
using System;
using Caliburn.Micro;
using System.ComponentModel;
namespace MyApp.Implementation
{
public class BackgroundCoRoutine : IResult
{
private readonly System.Action action;
public BackgroundCoRoutine(System.Action action)
{
this.action = action;
}
public void Execute(ActionExecutionContext context)
{
using (var backgroundWorker = new BackgroundWorker())
{
backgroundWorker.DoWork += (e, sender) => action();
backgroundWorker.RunWorkerCompleted += (e, sender) => Completed(this, new ResultCompletionEventArgs());
backgroundWorker.RunWorkerAsync();
}
}
public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
}
}
在我的一个ViewModel中,有以下内容:
public IEnumerable<IResult> ProcessTask()
{
IsBusy = true;
TempObject result = null;
for (int i = 1; i < 4; i++) // Simulates a loop that processes multiple items, files, fields...
{
yield return new BackgroundCoRoutine(() =>
{
System.Threading.Thread.Sleep(1000); // Time consuming task in another thread
result = new TempObject("Item " + i);
});
MyObservableCollection.Add(result); // Update the UI with the result, in the GUI thread
}
IsBusy = false;
}
这样,当我单击ProcessTask按钮时,UI不会被冻结,并且计算结果会在后台工作进程可用时立即显示。 IsBusy状态不是强制性的,但显示了与UI相关的状态如何进入面向异步的代码。
希望这会帮助我另一个人!
答案 1 :(得分:2)
您的问题是Coroutine.BeginExecute立即运行代码。您必须将代码运行为单独的任务或线程,或者在协程中调用异步代码。 Coroutine代码没有任何自动功能可以阻止您的UI阻止。