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

您可以使用易于使用的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 元素。Control.Invoke如果您想修改 UI 元素,您应该使用(eg this.Invoke)将调用编组回 UI 线程。有关更多详细信息,请参阅此帖子

于 2009-08-05T09:55:16.097 回答
2

在我的情况下,调试器 DO 进入 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 回答
1

伯恩霍夫可能是对的,但是要小心。所有 UI 元素都应该在同一个线程上执行。因此,如果您为 SFD 创建一个新线程,请确保您没有更新主窗口上的任何控件。

亲切的问候,纪尧姆·哈尼克

于 2009-08-05T10:01:41.807 回答