我有一个带有按钮的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()。
有谁知道我错过了什么?
谢谢。
答案 0 :(得分:2)
您可以使用易于使用的BackgroundWorker。
另外,我不确定在新线程中显示SaveFileDialog是否完全安全(我可能错了)。我的建议是这样的流程:
以下是一个示例实现,不使用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;
}