如何异步使用SaveFileDialog?

时间:2009-08-05 09:50:50

标签: winforms asynchronous savefiledialog

我有一个带有按钮的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 个答案:

答案 0 :(得分:2)

您可以使用易于使用的BackgroundWorker

另外,我不确定在新线程中显示SaveFileDialog是否完全安全(我可能错了)。我的建议是这样的流程:

  1. 在主线程上显示SaveFileDialog。
  2. 将文件名传递给方法,然后以异步方式调用该方法。
  3. 以下是一个示例实现,不使用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线程。有关详细信息,请参阅this post

答案 1 :(得分: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秒后将显示一个消息框

答案 2 :(得分:1)

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

亲切的问候, Guillaume Hanique

答案 3 :(得分:0)

你班上的

private object sync_temp = new object();

和线程方法

SaveFileDialog save = new SaveFileDialog();
// your code to do with "save"
Action ac = () => { lock (sync_temp) { save.ShowDialog(); } };
Invoke(ac);
//Thread.Sleep(10);
lock (sync_temp)
{
   string path = save.FileName;
}