2009-05-06 18 views
7

私はWinFormsプロジェクトでModel-View-Presenterパターンを使用していますが、フォームが発表者に何かを指示してからプレゼンターがそれをやるために行く間、反応しない。幸いにも私のプロジェクトでは、すべてのプレゼンターが非同期呼び出しを行うことに問題はありませんが、問題はどのように正確に行うのでしょうか?WinFormsを使用したMVPでの非同期呼び出しのベストプラクティス

各発表者のコールはちょうど新しいスレッドの作成に包まれるべきか?*

new Thread(()=>_presenter.DoSomething()).Start(); 

のベスト・プラクティスは、ここ何ですか?ユーザが「あなたのやっていることを中止する」ボタンを押すとどうなりますか?どのように私は正常に中止するのですか?

。*現実的に私はおそらくかなりのWinFormでスレッドの作成を置くよりも、これを行うにはプレゼンターのプロキシのいくつかの並べ替えを使用することになり

+0

ここに実際に参加していないことに驚いています。私もこれに興味があったでしょう。 – Houman

答えて

2

私はこれについて考えていると主張することができます(質問を読む前に)。まず、私は実際に重要な場所を調整します。 DBアクセスのチョークポイントなどです。 「UI」コンテキストで実行されるべきではない場所がある場合(UIスレッドでhttp://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.current.aspxから保存し、後で非UI同期コンテキストと比較することができます)、Debug.BitchAndMoan()を実行します。より長い計算(「自分のマニホールドですべて明確に分離されるべきである」)は、それを主張するべきである。

私は、プレゼンター機能の実行のタイプを、プロキシによって従う属性によって構成可能にする必要があります。 (ちょうどあなたが何かをシリアル形式でやりたいのであれば)。

タスクのキャンセルは実際にはプレゼンターの問題ですが、停止する内容を示す参照オブジェクトが必要です。プロキシの方法を使用すると、作成したスレッドをIAsyncResultでタスクリストに取り込むことができますが、同じアクションが複数回並行して呼び出されることが許されている場合、取り消される予定のスレッドを決定することはまだ問題です。そのため、タスクを開始するときに適切なコール固有の名前をタスクに指定する必要があります。これはView側にロジックが多すぎることを意味します。> PresenterはViewに、どのタスクを処分すべきかを尋ねる必要があります。

これは、通常、イベント(SCSFスタイル)を使用して回避されています。それを最初からやっていれば、私はSCSFが非常に多くの点で痛みを覚えていて、デザイナーの正気が疑わしいので、プロキシの方法をとっていきたいと思います。

+0

私のアプリケーションのチョークポイントにはあまりにも多くの問題がありますが、ユーザーのやりとりがプレゼンターにルーティングされる場所は5つまたは6つしかなく、すべて非同期であることができます。実際に新しいスレッドをスピンする方法はどうですか?新しいスレッド? BackgroundWorker?他に何か? –

+1

I _think_ BWは、常に「同じ」ことをする既知のタスクのためのものです。そのため、スポーンスレッドはここでは慣用的な.NETでなければなりません。あなたが何をしているかに応じて、スレッドプールを使用することができます:http://msdn.microsoft.com/en-us/library/ms973903.aspx。デフォルトではスレッドプールの深さは25ですので、これを設定/テストすることができます(新しいスレッドを生成するだけであればこの制限は適用されません) –

0

あなたはコールバックのカップルを受け入れる使用プロキシパターンを作成していないのはなぜ結果を返すか、中止するか?

+0

申し訳ありませんが、これは決して私の質問に答えません。私はベストプラクティスが非同期にコールを実行するために何を求めているのですか?新しいスレッド? BackgroundWorker?具体的に中止するには?私はコールバックを心配する必要はありません、これは伝統的なMVPなので、プレゼンターは実際に何も返しません。 –

4

私は通常(現実的に)別のタスク、のようなものの中に1秒か2秒以上かかることができます任意のアクション置く:私もこのようなタスクを実行するための抽象化を持って

public interface ITask 
{ 
    void ExecuteTask (ITaskExecutionContext context); 
    void AfterSuccess(ITaskExecutionContext context); 
    void AfterFailure(ITaskExecutionContext context); 
    void AfterAbortion(ITaskExecutionContext context); 
} 

public interface ITaskExecutor : IDisposable 
{ 
    void BeginTask(ITask task); 
    void TellTaskToStop(); 
} 

このITaskExecutorの実装の1つはBackgroundWorkerを使用している:

public class BackgroundTaskExecutor : ITaskExecutor 
{ 
    public void BeginTask(ITask task) 
    { 
     this.task = task; 
     worker = new BackgroundWorker(); 
     worker.DoWork += WorkerDoWork; 
     worker.RunWorkerCompleted += WorkerRunWorkerCompleted; 
     worker.WorkerSupportsCancellation = true; 

     worker.RunWorkerAsync(); 
    } 

    ... 
} 

私は依存関係注入とIoCを使って物事を結びつけることに重きを置きます。プレゼンターには、その後、私はちょうどのようなものを呼び出す:

GoAndDontReturnUntilYouBringMeALotOfMoneyTask task = new GoAndDontReturnUntilYouBringMeALotOfMoneyTask(parameters); 
taskExecutor.BeginTask(task); 

は/キャンセルボタンを中止し、その後、彼らは中止するタスク実行/タスクを伝えるように配線されています。

実際にはここに示したよりも少し複雑ですが、これは一般的な考えです。

+0

Execute、AfterSuccess、AfterFailure、AfterAbortionのlambdaを渡しますが、いいアドバイス。 –

+0

はい、あなたはlambdaでこれを行うことができますが、これは単純なタスクにのみ役立ちます。より複雑なタスクロジックは、それ自身のクラスにとって有益です。また、すべての "After"メソッドを実装する必要はありません。必要に応じてオーバーライドできる仮想メソッドを持つ基本抽象クラスを実装するのが最善です。 –

関連する問題