如何更新进度对话框?

时间:2014-03-25 14:43:44

标签: c# winforms visual-studio-2010 user-interface

我已经读过关于Invoke(ing)控件和诸如此类的东西......我不知道我应该调用什么控件,因为我的主窗体和对话框形式都有不止一个,因此我的问题在这里。我看过thisthis以及this ...我根本不明白如何将它应用到我的情况中。是否有某个教程我会去阅读以试图更好地理解?

我有一个winform应用程序(C#)做了一些工作。其中一些工作可能需要一段时间,所以我想我会提供各种进度对话框,提醒用户正在进行活动(而不是简单地依赖列表控件定期闪烁以指示更新的内容)。

所以,我在项目中添加了一个新表单,添加了一些感兴趣的项目(要处理的项目数,估计完成时间,当前项目和整体进度条)。

public ProgressDialog Progress { get; set; }

public Form1()
{
    Progress = new ProgressDialog(this);
    InitializeComponent();
    backgroundWorker1.WorkerReportsProgress = true;
    backgroundWorker1.WorkerSupportsCancellation = true;
}

单击“处理”按钮后,我将设置要在后台工作中完成的主要工作。

private void buttonProcess_Click(object sender, EventArgs e)
{
    if (backgroundWorker1.IsBusy != true)
    {
        backgroundWorker1.RunWorkerAsync();
        Progress.ShowDialog();
    }
}

从在该线程上调用的方法,我在ProgressDialog表单上调用一个方法:

Progress.UpdateDialog(numFiles: filesToProcess.Count, 
                      processTime: TimeSpan.FromTicks(filesToProcess.Count * TimeSpan.TicksPerSecond * 20)); // 20s is an estimated time, it will be updated after first file is processed.

有问题的代码(在ProgressDialog.cs中):

public void UpdateDialog(int percentComplete = 0, string fileName = "", int numFiles = 0, TimeSpan? processTime = null)
{
    ...
    if (numFiles > 0)
    {
        labelNumFiles.Text = Convert.ToString(numFiles);
    }
    if (!processTime.Equals(null))
    {
        labelProcessTime.Text = Convert.ToString(processTime);
    }
}

导致以下错误:

An exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll but was not handled in user code

Additional information: Cross-thread operation not valid: Control 'ProgressDialog' accessed from a thread other than the thread it was created on.

此外,主窗体有两个列表控件,需要在处理文件时更新:处理文件列表和错误文件列表。如果我有了添加进度对话框的好主意,那么一切正常。大声笑那么,处理更新进度对话框的正确方法是什么?

2 个答案:

答案 0 :(得分:0)

您必须使用Invoke()方法在用户控件表单中访问与创建线程的步骤不同的步骤

请参阅thisthis以更好地了解参数

答案 1 :(得分:0)

需要在UI线程上运行UpdateDialog方法,因为它正在进行UI工作。由于它是在DoWork的{​​{1}}期间调用的(很可能没有在您的UI线程上运行),因此您需要对Winforms使用InvokeRequired/Invoke模式:

BackgroundWorker