[英]Background Threads and Dialogs
我有一个小程序,它以应用栏开头(停靠在桌面上的窗口,可以隐藏起来(不使用时位于桌面的顶部,右侧,底部或左侧)。该程序允许用户拖动将文件从任意给定位置放到应用栏上,然后将其转换为PDF(通过将每个文件转换为PDF,然后将生成的PDF合并为一个PDF文件)。
转换过程使用后台工作程序在单独的线程上运行。 后台工作人员获取文件列表后,我将弹出一个模式对话框,其中已将相关文件加载到列表视图中,并允许用户在最终合并过程之前对其进行重新排序。
我在模式对话框中遇到跨线程问题。 我在高处和低处寻找解决方案,但感到困惑。 由于使用关键字this导致出现问题。
我在后台工作人员中尝试了以下代码:
using (var md = new MergeDlg())
{
md.Files = (string[])files;
if (md.ShowDialog(this) == DialogResult.OK)
files = md.Files;
}
如果我删除这个我没有得到任何错误的关键字,但是对话的行为如同它开始在主线程和backgroundworkerthread继续,如果没有模态对话框-据我所知, 是因为在主UI线程上开始对话。
我还尝试过将对话框的创建移出后台工作线程,并在线程中调用它以创建模态对话框的代码如下:
private string[] ShowMergeDlg(string[] files)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(() =>
{
MergeDlg md = new MergeDlg();
md.Files = (string[])files;
if (md.ShowDialog(this) == DialogResult.OK)
files = md.Files;
}
));
}
else
{
MergeDlg md = new MergeDlg();
md.Files = (string[])files;
if (md.ShowDialog(this) == DialogResult.OK)
files = md.Files;
}
return files;
}
在backgroundworker线程上,该函数称为:
files = ShowMergeDlg(files);
同样,该代码显然会以相同的结果在主UI线程上启动对话框。
我的问题是:
如何在后台工作程序线程上显示模式对话框,在线程对话框关闭之前暂停线程的执行?
您最好切换到异步/等待和任务。 这是一个非常有限的样本
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void button1_Click( object sender, EventArgs e )
{
button1.Enabled = false;
label1.Text = "acquire files ...";
ICollection<string> acquiredFiles = await AcquireFileAsync();
label1.Text = "select files ...";
ICollection<string> selectedFiles = SelectFilesDialog( acquiredFiles );
label1.Text = "process files ...";
await ProcessFilesAsync( selectedFiles );
label1.Text = "finished.";
button1.Enabled = true;
}
private async Task ProcessFilesAsync( ICollection<string> selectedFiles )
{
foreach (var item in selectedFiles)
{
await Task.Delay( 250 ).ConfigureAwait( false );
}
}
private ICollection<string> SelectFilesDialog( ICollection<string> acquiredFiles )
{
var dialog = new Form2();
dialog.ShowDialog();
return acquiredFiles;
}
private async Task<ICollection<string>> AcquireFileAsync()
{
await Task.Delay( 2500 ).ConfigureAwait( false );
return Enumerable.Range( 1, 20 ).Select( e => e.ToString() ).ToList();
}
}
如果从后台工作程序调用ShowMergeDlg
,则InvokeRequired
为true,然后在UI线程上创建对话框。 因此,只需删除它,让对话框在后台线程中创建。
private string[] ShowMergeDlg(string[] files)
{
/*
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(() =>
{
MergeDlg md = new MergeDlg();
md.Files = (string[])files;
if (md.ShowDialog(this) == DialogResult.OK)
files = md.Files;
}
));
}
else
*/
{
MergeDlg md = new MergeDlg();
md.Files = (string[])files;
if (md.ShowDialog(this) == DialogResult.OK)
files = md.Files;
}
return files;
}
我的测试代码
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 5; ++i)
{
this.Invoke(new Action(() => textBox1.AppendText("1")));
Thread.Sleep(500);
}
var f2 = new Form2();
if(f2.ShowDialog(this) == DialogResult.OK)
this.Invoke(new Action(() => textBox1.AppendText("2")));
else
this.Invoke(new Action(() => textBox1.AppendText("3")));
for (int i = 0; i < 100; ++i)
{
this.Invoke(new Action(() => textBox1.AppendText("1")));
Thread.Sleep(500);
}
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.