4

外部サーバーから一連の更新を取得してインストールするアプリに取り組んでおり、スレッド化の助けが必要です。ユーザーは次のプロセスに従います。

  • ボタンのクリック
  • メソッドは更新をチェックし、count が返されます。
  • 0 より大きい場合は、MessageBox.Show() を使用してインストールするかどうかをユーザーに尋ねます。
  • はいの場合、ループを実行し、各更新の run() メソッドで BeginInvoke() を呼び出して、バックグラウンドで実行します。
  • 私の更新クラスには、進行状況バーなどを更新するために使用されるいくつかのイベントがあります。

進行状況バーの更新は問題ありませんが、ユーザーが [はい] をクリックした直後に更新ループが開始されるため、MessageBox は画面から完全に消去されません (下のスクリーンショットを参照)。

  • 更新ループが始まる前にメッセージボックスを即座に非表示にするにはどうすればよいですか?
  • BeginInvoke() の代わりに Threads を使用する必要がありますか?
  • 別のスレッドで最初の更新チェックを行い、そのスレッドから MessageBox.Show() を呼び出す必要がありますか?

コード

// Button clicked event handler code...
DialogResult dlgRes = MessageBox.Show(
    string.Format("There are {0} updates available.\n\nInstall these now?", 
    um2.Updates.Count), "Updates Available", 
    MessageBoxButtons.YesNo, 
    MessageBoxIcon.Question, 
    MessageBoxDefaultButton.Button2
);

if (dlgRes == DialogResult.Yes)
{
    ProcessAllUpdates(um2); 
}

// Processes a bunch of items in a loop
private void ProcessAllUpdates(UpdateManager2 um2)
{
    for (int i = 0; i < um2.Updates.Count; i++)
    {
        Update2 update = um2.Updates[i];

        ProcessSingleUpdate(update);

        int percentComplete = Utilities.CalculatePercentCompleted(i, um2.Updates.Count);

        UpdateOverallProgress(percentComplete);
    }
}

// Process a single update with IAsyncResult
private void ProcessSingleUpdate(Update2 update)
{
    update.Action.OnStart += Action_OnStart;
    update.Action.OnProgress += Action_OnProgress;
    update.Action.OnCompletion += Action_OnCompletion;

    //synchronous
    //update.Action.Run();

    // async
    IAsyncResult ar = this.BeginInvoke((MethodInvoker)delegate() { update.Action.Run(); });
}

スクリーンショット

Windows モバイルのバグ

4

3 に答える 3

6

すべての作業がユーザー インターフェイス スレッドで行われているため、UI が更新されていません。あなたの電話番号:

this.BeginInvoke((MethodInvoker)delegate() {update.Action.Run(); }) 

ユーザーインターフェイススレッドである「これ」(フォーム)を作成したスレッドで update.Action.Run() を呼び出すと言っています。

Application.DoEvents()

確かに、UI スレッドに画面を再描画する機会を与えますが、新しいデリゲートを作成して、その上で BeginInvoke を呼び出したくなるでしょう。

これにより、スレッド プールから割り当てられた別のスレッドで update.Action.Run() 関数が実行されます。次に、更新が完了するまで IAsyncResult をチェックし続け、チェックごとに更新オブジェクトの進行状況を照会し (他のスレッドに進行状況バー/UI を更新させることができないため)、Application.DoEvents() を呼び出します。

また、後で EndInvoke() を呼び出すことになっています。そうしないと、リソースがリークする可能性があります

また、進行状況ダイアログにキャンセル ボタンを配置し、タイムアウトを追加することもできます。そうしないと、更新が停止した場合 (または時間がかかりすぎる場合)、アプリケーションが永久にロックされてしまいます。

于 2008-08-13T18:17:23.483 に答える
1

入れてみましたか

Application.DoEvents()

ここに

if (dlgRes == DialogResult.Yes)
{
   Application.DoEvents(); 
   ProcessAllUpdates(um2); 
}
于 2008-08-13T17:37:08.167 に答える
1

@ジョン・シブリー

WinForms を扱うときに EndInvokeを呼び出さなくても、悪影響はありません。

私が知っている唯一の文書化されたルールの例外は、Windows フォームにあります。ここでは、Control.EndInvoke を呼び出さずに Control.BeginInvoke を呼び出すことが正式に許可されています。

ただし、Begin/End Async パターンを処理する他のすべてのケースでは、前述のようにリークすると想定する必要があります。

于 2008-08-21T20:21:42.187 に答える