2012-02-07 7 views
0

私はC#と.NET 4.0で作業しています。システムメッセージの流れを止めることなく、フロントエンドが長いプロセスを待つ方法が必要です

私のプログラムは、フロントエンドとバックエンドで構成されています。バックエンドは、システムの起動時に自動的に起動するWindowsサービスとして実行されます。フロントエンドは、アプリケーションを使用する準備ができたときにユーザーが開始するWPFアプリケーションです。

スタートアッププロセスの一部として、フロントエンドはバックエンドとの通信を確立する必要があります。これはXMPPを使用して行われ、正常に動作します。通信を行うコードには、WaitHandleを返すBeginStartメソッドがあります。 try-catchの中で、私はBeginStartを呼び出し、WaitHandleを取得し、WaithandleのWaitOne(TimeSpan)メソッドを呼び出します。この時点でプログラムはスプラッシュスクリーンを表示していることに注意してください。そして、これらの呼び出しはフロントエンドスレッドで行われています。

これは正常に動作していますが、WaitOneコールの実行中に他のウィンドウをクリックしても効果はありません。基本的に、すべてのWindowsメッセージトラフィックは、このWaitHandleが戻るのを待って停止します。

私はBeginStartとWaitOneの呼び出しを別のスレッドで行う必要があると思います。 WaitOne呼び出しが正常に返されない限り(タイムアウトなし)、プログラムが終了し、ユーザーインターフェイスが表示されないため、WaitOneが戻るのを待つためにフロントエンドが必要です。他のプログラムがWindowsメッセージを処理できるようにするだけです。

この作品を作成するにはどうすればよいですか? WPFにはApplication.DoEventsメソッドはありません。

トニー

は編集:

私はいくつかのより多くの情報を提供する場合、それは役に立つかもしれように見えます。

私のWPFアプリケーションは、この製品のユーザーインターフェイスであり、製品全体の半分のみを構成します。残りの半分は同じPC上でWindowsサービスとして実行されており、バックエンドと呼んでいます。バックエンドで何が起こっているかは、XMPPを使用して接続をリスンしていることを除いて、重要ではありません。

ユーザーインターフェイス(またはフロントエンド)が起動すると、XMPPを使用してバックエンドとの通信を確立する必要があります。これは通常最大で2〜2回かかります。ただし、ユーザーがフロントエンドを起動したときに何か問題が発生したり、バックエンドが停止したりする可能性があります。私はフロントエンドが無期限に待つことを望まない。それは合理的な時間の後にタイムアウトし、エラーメッセージを表示して死ぬ必要があります。

通信を確立するには、別のスレッドとして起動するモジュールがあります。私はWaitHandleを返すBeginStartメソッドを呼び出しています。私はWaitHandleを待ち、TimeSpanをタイムアウト期間に渡します。スニペットは次のとおりです。

try { 
    WaitHandle handle = BackgroundProcess.BeginStart(); 
    if (!handle.WaitOne(Timeout)) { 
     // Something went wrong; Notify user here 
     return false; 
    } 

    // Make sure that the Background Process has started all of it's internal modules 
    bool allAreRunning; 
    Stopwatch timer = new Stopwatch(); 
    timer.Reset(); timer.Start(); 
    do { 
     allAreRunning = true; 
     foreach (Module module in BackgroundProcess.Modules) { 
      if (module.State != Module.States.Running) { 
       allAreRunning = false; 
       break; 
      } 
     } 

     if (!allAreRunning) { 
      // I hate this loop, but I can't think of a better way to do this 
      Thread.Sleep(1000); 
     } 

    } while (!allAreRunning && timer.ElapsedMilliseconds <= Timeout.TotalMilliseconds); 

    timer.Stop(); 

    if (!allAreRunning) { 
     // Something went wrong; Notify user here 
     return false; 
    } 

    // Other initialization done here 

} catch (Exception ex) { 
    // Something went wrong; Notify user here 
    return false; 
} 

これをテストするには、バックエンドがダウンしている間にデバッガでプログラムを実行してください。私は開いているウィンドウをクリックしてそれに切り替え、それとうまくやりとりすることができます。私ができないことは、デスクトップをクリックすることです。 WaitHandle.WaitOne()呼び出しは非常に迅速に戻ります。バックグラウンドプロセスの実行が開始され、接続が確立されるのを待たずに戻ります。これは、ほとんどのタイムアウト期間に実行されるdo-whileループです。

これを書き直す必要があるため、ユーザーはプログラムを開くだけでなく、デスクトップをクリックすることもできます。私はちょうどそれを動作させる方法を知らない。

トニー

+0

プログラムは、システム上の他のすべてのプログラムをブロックしてはならないワン:

コードは次のようになります。コードスニペットを投稿できますか? –

答えて

0

私はこの起動ロジックをコードするより良い方法を見つけました。しかし、コードは内部コードのアーキテクチャに依存しています。

コードスニペットでdo-whileループを削除し、より良いコードに置き換えることができました。ここで、コードはすべてのModuleオブジェクトをループし、実行状態WaitHandleを問い合わせます。これらはListコレクションに追加されます。ループが完了したら、Listを配列に変換して.ToArray()を呼び出し、WaitHandle.WaitAllメソッドを呼び出します。

try { 
    WaitHandle handle = BackgroundProcess.BeginStart(); 
    if (!handle.WaitOne(Timeout)) { 
     . . . 
     return false; 
    } 

    List<WaitHandle> waitHandles = new List<WaitHandle>(); 
    foreach (Module module in BackgroundProcess.Transit.SubModules) { 
     WaitHandle waitHandle = module.GetWaitHandleForState(Module.States.Running); 
     waitHandles.Add(waitHandle); 
    } 

    if (!WaitHandle.WaitAll(waitHandles.ToArray(), Timeout)) { 
     . . . 
     return false; 
    } 

    // If we get here, everything is communicating properly. 
    . . . 

} catch (Exception ex) { 
    . . . 
    return false; 
} 

return true; 

おかげ

トニー

1

あなたはBackgroundWorkerにお電話を移動したときに完成したロードWorkerCompletedイベントをキャッチすることができます。また、ProgressChangedイベントを通じてUIの進捗状況を更新することもできます。

+0

スプラッシュ画面が表示されている間、プロセスが実行されています。更新するUIには何もありません。そして、私は、バックグラウンドプロセスがアプリケーションの一部であるWindowsサービスとの接続を確立するのを待っています。進歩はありません。私の元の質問に私の編集を参照してください。 –

+0

スレッドが復帰するのをどのように待っていますか?メインスレッドが子スレッドが終了するのを待っているコードを投稿できますか?メインスレッドがまだ実行されているような方法で実行する可能性があります。 – rie819

+0

私はあなたがASP.NETでこれをやろうとしていることに気がつきました。 ASP.NETでスレッドしないでください。あなたのWebページからWebサービスコールを行うことはできますが、ASP.NETアプリケーションをマルチスレッド化することはお勧めしません。 – rie819

関連する問題