后台线程和对话框

时间:2019-02-21 00:54:26

标签: c#

我有一个小程序,它以应用栏开头(停靠在桌面上的窗口,可以隐藏起来(不使用时位于桌面的顶部,右侧,底部或左侧)。用户将文件从任意给定位置拖到应用栏上,然后将其转换为PDF(通过将每个文件转换为PDF,然后将生成的PDF合并为一个PDF文件)。

使用后台工作程序在单独的线程上运行转换过程。后台工作人员获取文件列表后,我将弹出一个模式对话框,并在其中加载了相关文件的列表视图,并允许用户在最终合并过程之前对其进行重新排序。

我在模式对话框中遇到跨线程问题。我在高处和低处寻找解决方案,但感到困惑。由于使用关键字this导致出现问题。

我在后台工作人员中尝试了以下代码:

using (var md = new MergeDlg())
{
    md.Files = (string[])files;
    if (md.ShowDialog(this) == DialogResult.OK)
        files = md.Files;
}

如果我删除关键字 this ,我不会出错,但是对话框的行为就像是在主线程上启动的,而backgroundworkerthread就像没有模式对话框一样继续运行-我理解< strong> ,因为该对话框是在主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线程上启动对话框。

我的问题是:

如何在backgroundworker线程上显示模式对话框,在线程对话框关闭之前暂停执行线程?

2 个答案:

答案 0 :(得分:1)

您最好切换到异步/等待和任务。这里的样本非常有限

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();
    }
}

答案 1 :(得分:0)

如果从后台工作人员调用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();
    }
}

Screenshot