14

私の質問はたくさんあります。私が見たので。NET 4.5、私は非常に感銘を受けました。残念ながら、私のプロジェクトはすべて.NET 4.0であり、移行については考えていません。そこで、コードを単純化したいと思います。

現在、画面をフリーズするのに通常十分な時間がかかる私のコードのほとんどは、次のことを行います。

BackgroundWorker bd = new BackgroundWorker();
bd.DoWork += (a, r) =>
    {
        r.Result = ProcessMethod(r.Argument);
    };
bd.RunWorkerCompleted += (a, r)  =>
    {
        UpdateView(r.Result);
    };

bd.RunWorkerAsync(args);

正直なところ、私はそれにうんざりしています。そして、論理的に複雑なユーザーインタラクションがある場合、それは大きな問題になります。

このロジックを単純化する方法は?(私は.Net 4.0を使用していることを忘れないでください)グーグルでいくつかのことに気づきましたが、実装が簡単で私のニーズに適したものは見つかりませんでした。

私はこの解決策を以下で考えました:

var foo = args as Foo;
var result = AsyncHelper.CustomInvoke<Foo>(ProcessMethod, foo);
UpdateView(result);

public static class AsyncHelper
{
    public static T CustomInvoke<T>(Func<T, T> func, T param) where T : class
    {
        T result = null;
        DispatcherFrame frame = new DispatcherFrame();
        Task.Factory.StartNew(() =>
        {
            result = func(param);
            frame.Continue = false;
        });

        Dispatcher.PushFrame(frame);

        return result;
    }
}

ディスパッチャフレームの操作に影響があるかどうかはわかりません。しかし、私はそれが非常にうまく機能することを知っています。たとえば、画面をフリーズすることなく、コントロールのすべてのイベントで使用できます。ジェネリック型、共変性、反変性についての私の知識は限られています。おそらくこのコードは改善できるでしょう。

Task.Factory.StartNewとを使って他のことを考えましたがDispatcher.Invoke、面白くて使いやすいとは思えません。誰かが私にいくつかの光を与えることができますか?

4

3 に答える 3

15

タスク並列ライブラリ(TPL)を使用する必要があります。重要なのは、UIを更新する継続TaskSchedulerの現在のを指定することです。SynchronizationContext例えば:

Task.Factory.StartNew(() =>
{
    return ProcessMethod(yourArgument);
})
.ContinueWith(antecedent =>
{
    UpdateView(antecedent.Result);
},
TaskScheduler.FromCurrentSynchronizationContext());

Result先行詞のプロパティにアクセスするときのいくつかの例外処理を除けば、それだけです。FromCurrentSynchronizationContext()WPFからのアンビエントSynchronizationContext(つまり、DispatcherSynchronizationContext)を使用して、継続を実行します。これは呼び出しと同じDispatcher.[Begin]Invokeですが、完全に抽象化されています。

さらに「よりクリーン」にしたい場合、ProcessMethodを制御する場合は、実際にそれを書き直してaを返し、Taskそれがどのようにスピンアップするかを自分のものにします(引き続きStartNew内部で使用できます)。このようにして、ProcessMethodが独自に行う可能性のある非同期実行の決定から呼び出し元を抽象化し、代わりに、結果を待つために継続の連鎖について心配するだけで済みます。

2013年5月22日更新

await Task.Run.NET 4.5の登場とC#での非同期言語のサポートにより、この規定された手法は時代遅れになり、これらの機能を使用して特定のタスクを実行し、その後、ディスパッチャースレッドで実行されることに注意してください。再び自動的に。だからこのようなもの:

MyResultType processingResult = await Task.Run(() =>
{
    return ProcessMethod(yourArgument);
});

UpdateView(processingResult);
于 2012-09-10T18:03:30.457 に答える
1

再利用可能なコンポーネントで常に同じであるコードをカプセル化するのはどうですか?ICommandを実装し、タイプDoWorkEventHandlerのプロパティとResultプロパティを公開するFreezableを作成できます。ICommand.Executedでは、BackgroundWorkerを作成し、DoWorkとCompletedのデリゲートを接続し、DoWorkEventHandlerの値をイベントハンドラーとして使用し、独自のResultプロパティをイベントで返された結果に設定する方法でCompletedを処理します。 。

XAMLでコンポーネントを構成し、コンバーターを使用してDoWorkEventHandlerプロパティをViewModelのメソッドにバインドし(私はあなたが持っていると思います)、ビューをコンポーネントのResultプロパティにバインドして、結果が発生したときに自動的に更新されるようにします変更通知を行います。

このソリューションの利点は次のとおりです。再利用可能であり、XAMLでのみ機能するため、BackgroundWorkersを処理するためだけにViewModelにグルーコードを追加する必要はありません。進行状況を報告するためにバックグラウンドプロセスが必要ない場合は、バックグラウンドスレッドで実行されていることに気付かない可能性もあるため、XAMLで、メソッドを同期的に呼び出すか非同期的に呼び出すかを決定できます。

于 2012-09-12T18:07:47.943 に答える
0

数ヶ月が経ちましたが、これはあなたを助けることができますか?
.NETFramework4.5なしでasync/awaitを使用する

于 2013-03-22T10:45:31.433 に答える