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 コルーチンを使用した非同期操作) を見つけたので、それを共有できるようにします。

私が理解している限り、Caliburn のコルーチンはスレッドを処理しません。それらは、非同期実行と制御コードを 1 つのメソッドで処理するエレガントな方法を提供するだけです。バックグラウンド スレッドで操作を処理するには、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 { };

    }
}

そして、私の ViewModels の 1 つでは、次のようになります。

    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

Your issue is that the Coroutine.BeginExecute runs the codes immediately. You have to either run the code an a separate Task or Thread, or call asynchronous code within your coroutine. There is nothing automatic about Coroutine code that will stop your UI from blocking.

于 2012-08-16T21:17:37.407 に答える
1

Caliburn.Micro コルーチンは、非同期ルーチンを同期的に実行するのに役立ちます。その逆ではありません。あなたの問題に関して:すぐに使えるCMは、解決策を非常に迅速に見つける可能性を提供します... ;-)

やりたいことを達成するには、.NET BackgroundWorker を見て、その周りにコルーチン (IResult) を作成することをお勧めします。

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

于 2012-08-17T12:05:47.590 に答える