0

从文档中我意识到我可以使用 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();
    }

    // ...
}

简单任务:

public class SimpleTask : IResult 
{
    public void Execute(ActionExecutionContext context)
    {
        Thread.Sleep(10000);
    }

    public event EventHandler<ResultCompletionEventArgs> Completed;
}

我希望 Execute 方法中的代码能够异步运行。但这不会发生。我的 UI 线程被阻塞了 10 秒。

我在哪里做错了?或者我对协程异步性质的假设是错误的?

4

3 回答 3

12

我花了一整天的时间寻找和尝试代码示例,最终得到了一些可行的东西(即使用不阻塞 UI 的 Caliburn Coroutines 的异步操作),所以我允许自己分享它。

据我了解,Caliburn 中的协程不处理线程,它们只是提供了一种优雅的方式来以一种方法处理异步执行和控制代码。必须使用 BackgroundWorkers 等其他工具来处理后台线程中的操作。

对于silverlight,我发现此链接非常有趣。目的是将后台工作人员包含在一个包装协程调用的类中。

由于我希望它在 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 相关状态如何进入面向异步的代码。

希望这会帮助另一个我!

于 2012-11-22T15:42:03.840 回答
2

您的问题是 Coroutine.BeginExecute 立即运行代码。您必须在单独的任务或线程中运行代码,或者在协程中调用异步代码。协程代码不会自动阻止您的 UI 阻塞。

于 2012-08-16T21:17:37.407 回答
1

Caliburn.Micro Coroutines 帮助您以同步方式执行异步例程。不是反过来。关于您的问题:开箱即用的 CM 为您提供了快速找到解决方案的可能性... ;-)

为了完成您想做的事情,我建议您查看 .NET BackgroundWorker 并围绕它创建一个协程 (IResult)。

http://caliburnmicro.codeplex.com/discussions/391929

于 2012-08-17T12:05:47.590 回答