2

ボタン付きの Windows フォーム アプリケーションがあります。ボタンのイベント ハンドラで、SaveFileDialog を使用してファイルをダウンロードする必要があります。しかし、これを別のスレッドで非同期に行う必要があります。

これまでのところ、このコードを思いつきましたが、私のアプローチに欠陥があるかどうかはわかりません。

        private void btnDownload_Click(object sender, EventArgs e)
        {
                ThreadStart tStart = new ThreadStart(DoWorkDownload);
                Thread thread = new Thread(tStart);
                thread.SetApartmentState(ApartmentState.STA);
                thread.Start();
        }

        private void DoWorkDownload()
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.InitialDirectory = "C:\\";
            sfd.Filter = "All files (*.*)|*.*";
            sfd.FilterIndex = 1;
            sfd.RestoreDirectory = true;

            if (sfd.ShowDialog() == DialogResult.OK)
            {
            //do file saving here
            }
        }
}

上記のコードの私のロジックは次のとおりです。ボタンをクリックして新しいスレッドを作成し、 DoWorkDownload() メソッドをスレッドに渡してから開始します。その時点で作業メソッドに入ることになっていますが、デバッグ時には DoWorkDownload() に入ることはありません。

誰かが私が欠けているものを知っていますか?

ありがとうございました。

4

3 に答える 3

2

私の場合、デバッガーは DoWorkDownload() に入ります btnDownload_Click() の終了後に入ります SaveFileDialog sfd = new SaveFileDialog(); にブレークポイントを設定します。そしてそれはうまくいくはずです

非同期で動作することを証明するために、次のコードを追加しました

ThreadStart tStart = new ThreadStart(DoWorkDownload);
Thread thread = new Thread(tStart);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

Thread.Sleep(10000);
MessageBox.Show("qwe");

デバッガーなしで実行すると、現在のスレッドがスリープ状態になると、SaveFileDialog が表示され、10 秒後にのみメッセージ ボックスが表示されることがわかります。

于 2009-08-05T10:03:28.467 に答える
2

使いやすいBackgroundWorkerを使用できます。

また、新しいスレッドで SaveFileDialog を表示することが完全に安全かどうかはわかりません (間違っている可能性もあります)。私の推奨事項は、次のようなフローです。

  1. メインスレッドで SaveFileDialog を表示します。
  2. ファイル名をメソッドに渡します。メソッドは非同期的に呼び出されます。

を使用しない実装例を次に示しますBackgroundWorker

private void button1_Click(object sender, EventArgs e)
{
  SaveFileDialog sfd = new SaveFileDialog();
  sfd.InitialDirectory = "C:\\";
  sfd.Filter = "All files (*.*)|*.*";
  sfd.FilterIndex = 1;
  sfd.RestoreDirectory = true;
  if (sfd.ShowDialog() == DialogResult.OK)
  {
    // Invoke the SaveFile method on a new thread.
    Action<string> invoker = new Action<string>(SaveFile);
    invoker.BeginInvoke(sfd.FileName, OnSaveFileCompleted, invoker);
  }
}

protected void SaveFile(string fileName)
{
  // save file here (occurs on non-UI thread)
}

protected void OnSaveFileCompleted(IAsyncResult result)
{
  Action<string> invoker = (Action<string>) result.AsyncState;
  invoker.EndInvoke(result);
  // perform other actions after the file has been saved (also occurs on non-UI thread)
}

非 UI スレッドで実行されるすべてのアクションは、非 UI 要素にのみ影響する必要があることに注意してください。UI 要素を変更する場合は、Control.Invoke(例: this.Invoke) を使用して、UI スレッドへのコールバックをマーシャリングする必要があります。詳細については、この投稿を参照してください。

于 2009-08-05T09:55:16.097 に答える
1

ベルンホフは正しいかもしれませんが、注意してください。すべての UI 要素は同じスレッドで実行する必要があります。そのため、SFD 用の新しいスレッドを作成する場合は、メイン ウィンドウのコントロールを更新しないようにしてください。

敬具、 ギヨーム・ハニーク

于 2009-08-05T10:01:41.807 に答える