Sab*_*abz 1 c# multithreading backgroundworker sta showdialog
经过2个小时的研究,我仍然找不到解决我的问题的方法。
我所做的任务是在 BackGroundWorker 线程中处理一些文件。但是,有时我需要使用 ShowDialog 让用户选择 SaveFile 位置,但我收到 STA/MTA 错误。
主窗体代码:
private void button2_Click(object sender, EventArgs e)
{
button1.Enabled = false;
ProcessReportWorker.RunWorkerAsync();
}
Run Code Online (Sandbox Code Playgroud)
工作代码:
void ProcessReportWorker_DoWork(object sender, DoWorkEventArgs e)
{
int ReportCount = Reports.Count();
foreach (string Report in Reports)
{
ProcessReport NewReport = new ProcessReport(Report);
string result = NewReport.Start();
}
}
Run Code Online (Sandbox Code Playgroud)
ProcessReport.Start() 代码:
class ProcessReport
{
public string Start()
{
if(File.Exists(ResultPath))
{
SaveFileDialog SaveReport = new SaveFileDialog();
SaveReport.InitialDirectory = "c:\somepath";
SaveReport.CheckPathExists = true;
SaveReport.DefaultExt = ".xls";
SaveReport.OverwritePrompt = true;
SaveReport.ValidateNames = true;
if (SaveReport.ShowDialog() == DialogResult.OK)
{
ResultPath = SaveReport.FileName;
if (File.Exists(ResultPath)) File.Delete(ResultPath);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,在某些情况下需要 ShowDialog。我相信这可以使用代表来完成,但我对代表不太熟悉。我确实尝试了 Jon 在Calling ShowDialog in BackgroundWorker中提出的解决方案,但我无法让它工作。(也许我对代表做错了什么?)
请有人帮我解决这个问题。如果需要,请向我提供代表代码。谢谢!
编辑: PoweredByOrange 给出的解决方案有效。但是,我必须对其进行一些小更改:
this.Invoke((MethodInvoker)delegate{....}); 不起作用,因为 - 目的是引用 MainForm 实例,但此代码存在于 ProcessReport 类中。所以这里的“ this ”指的是ProcessReport类实例,但它必须引用GUI实例(MainForm实例)才能工作。
我的修复:我将 MainForm 的实例发送到 ProcessReport 类并进行了如下更改:
在工作中:
ProcessReport NewReport = new ProcessReport(Report, this); //CHANGE: Sending 'this'
//this sends reference of MainForm(GUI) to the ProcessReport Class
Run Code Online (Sandbox Code Playgroud)
在 ProcessReport 类中:
class ProcessReport
{
MainForm MainFormInstance;
public ProcessReport(string report, MainForm x)
{
MainFormInstance = x;
}
public string Start()
{
MainFormInstance.Invoke((MethodInvoker)delegate //changed this.Invoke to MainFormInstance.Invoke
{
SaveFileDialog SaveReport = new SaveFileDialog();
SaveReport.InitialDirectory = "c:\somepath";
SaveReport.CheckPathExists = true;
SaveReport.DefaultExt = ".xls";
SaveReport.OverwritePrompt = true;
SaveReport.ValidateNames = true;
if (SaveReport.ShowDialog() == DialogResult.OK)
{
ResultPath = SaveReport.FileName;
if (File.Exists(ResultPath)) File.Delete(ResultPath);
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
于是上面的事情终于成功了。感谢 PoweredByOrange,我非常清楚这一点。
您收到异常的原因是因为只有拥有控件的线程才允许修改/访问它。在这种情况下,该方法SaveFileDialog属于您的主线程,但该Start()方法正在不同的(即后台)线程中运行。因此,这种情况下的后台线程需要请求主线程打开其 SaveFileDialog。
public string Start()
{
if(File.Exists(ResultPath))
{
this.Invoke((MethodInvoker)delegate
{
SaveFileDialog SaveReport = new SaveFileDialog();
SaveReport.InitialDirectory = "c:\somepath";
SaveReport.CheckPathExists = true;
SaveReport.DefaultExt = ".xls";
SaveReport.OverwritePrompt = true;
SaveReport.ValidateNames = true;
if (SaveReport.ShowDialog() == DialogResult.OK)
{
ResultPath = SaveReport.FileName;
if (File.Exists(ResultPath)) File.Delete(ResultPath);
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
为了更清楚地说明这一点,假设您希望您的朋友给您一本他的教科书。你不可以去你朋友的房间偷书。你可以做的是打电话给你的朋友(invoke)并请求帮助(delegate)。
| 归档时间: |
|
| 查看次数: |
5977 次 |
| 最近记录: |