【问题标题】:BackgroundWorker ShowDialog causes app to stopBackgroundWorker ShowDialog 导致应用程序停止
【发布时间】:2012-08-13 20:21:03
【问题描述】:

我一直在尝试在我的应用程序中实现一个 BackgroundWorker,但到目前为止,进展并不顺利。在一个新线程上,我想打开一个新的表单,它有一个进度条和一个标签来报告进度,但是,这不是很好。当我调用 ShowDialog 时,应用程序不再响应。这是因为我的代码是从我的 Form1 运行的,并且我正在显示 WorkingForm?另外,这可以更干净地实现吗?

private void button14_Click(object sender, EventArgs e)
{
    List<object> param = new List<object>();
    object[] objectparams = new object[1];
    objectparams[0] = null;
    Opera opera = new Opera();
    System.Reflection.MethodInfo clearOpera = opera.GetType().GetMethod("ClearOpera");
    param.Add(clearOpera);
    param.Add(opera);
    param.Add(objectparams);
    backgroundWorker1.RunWorkerAsync(param);
}

private void button2_Click_1(object sender, EventArgs e)
{
    Browser.cancelPending = true;
}
private delegate void getnewform();

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    mainForm main = new mainForm();
    TestURLGUI4.Form1 form = (TestURLGUI4.Form1)Application.OpenForms[0];
    var variab = (bool)form.Invoke(new getnewform(main.AskForConfirmation));
        List<object> param = e.Argument as List<object>;

        List<object> result = new List<object>();
        var method = param[0] as MethodInfo;
        object[] parameters = param[2] as object[];
        if (parameters[0] == null)
        {
            result.Add(method.Invoke(param[1], null));
            result.Add(false);
        }
        else
        {
            result.Add(method.Invoke(param[1], parameters));
            if (parameters.Contains(true))
                result.Add(true);
        }
        int progress = (100 * Browser.progressValue) / Browser.progressMax;

        backgroundWorker1.ReportProgress(progress);

        // If the BackgroundWorker.CancellationPending property is true, cancel
        if (backgroundWorker1.CancellationPending)
        {
            Console.WriteLine("Cancelled");
            Browser.cancelPending = true;
        }
        e.Result = result;
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
        TestURLGUI4.WorkingForm form = (TestURLGUI4.WorkingForm)Application.OpenForms[1];
        form.progressBar1.Value = e.ProgressPercentage;

        form.label1.Text = Browser.progressValue + "/" + Browser.progressMax;
        Application.DoEvents();
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    List<object> param = e.Result as List<object>;
    if (e.Cancelled == false && param.Contains(true))
    {
        Display.DisplayURLs(param[0] as SortableBindingList<URL>);
        TestURLGUI4.WorkingForm form = (TestURLGUI4.WorkingForm)Application.OpenForms[1];
        MessageBox.Show("Done");

    }
    else if (e.Cancelled == false && param.Contains(false))
    {
        TestURLGUI4.WorkingForm form = (TestURLGUI4.WorkingForm)Application.OpenForms[1];
        MessageBox.Show("Done");
    }


}

    public class mainForm
{
public void AskForConfirmation()
{
    TestURLGUI4.Form1 form = (TestURLGUI4.Form1)Application.OpenForms[0];
    var workingForm = new TestURLGUI4.WorkingForm();
    workingForm.ShowDialog(form);
    workingForm.DialogResult = DialogResult.None;

}
}

编辑: 好的,我已经根据建议更新了我的代码,现在,这会在 System.Windows.Forms.dll 中产生一个 stackoverflowexception:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    mainForm main = new mainForm();
    TestURLGUI4.Form1 form = (TestURLGUI4.Form1)Application.OpenForms[0];
        List<object> param = e.Argument as List<object>;
        List<object> result = new List<object>();
        var method = param[0] as MethodInfo;
        object[] parameters = param[2] as object[];
        if (parameters[0] == null)
        {
            result.Add(method.Invoke(param[1], null));
            result.Add(false);
        }
        else
        {
            result.Add(method.Invoke(param[1], parameters));
            if (parameters.Contains(true))
                result.Add(true);
        }
        int progress = (100 * Browser.progressValue) / Browser.progressMax;

        backgroundWorker1.ReportProgress(progress);

        // If the BackgroundWorker.CancellationPending property is true, cancel
        if (backgroundWorker1.CancellationPending)
        {
            Console.WriteLine("Cancelled");
            Browser.cancelPending = true;
        }
        e.Result = result;


}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    TestURLGUI4.Form1 form1 = (TestURLGUI4.Form1)Application.OpenForms[0];
    if (Application.OpenForms.Count >= 2)
    {
        TestURLGUI4.WorkingForm form2 = (TestURLGUI4.WorkingForm)Application.OpenForms[1];
        form2.progressBar1.Value = e.ProgressPercentage;

        form2.label1.Text = Browser.progressValue + "/" + Browser.progressMax;
        Application.DoEvents();
    }
    else if(Application.OpenForms.Count == 1)
    {
        var workingForm = new TestURLGUI4.WorkingForm();
        workingForm.ShowDialog(form1);
    }
}

【问题讨论】:

  • 让您的生活更轻松。在启动线程之前进行确认,并完全消除对 Application.OpenForms 的需求。这是一场几乎可以保证的比赛,在您获得参考后,表格可能会关闭。甚至不想考虑在对应用程序进行一些更改后,对它的显式索引可能会给您留下什么。
  • 有人可以看看我更新的代码吗?

标签: c# user-interface backgroundworker


【解决方案1】:

BackgroundWorker 的目的是调用另一个线程(不是 UI 线程)上的代码。通过在DoWork 方法中调用Invoke,您完全绕过了BackgroundWorker 的用途。在启动 worker 之前完成所有 UI 工作。如果您需要在工作人员工作时与用户交互,请在ProgressChanged 处理程序中进行 - 它在 UI 线程上运行,您不需要在 @ 中使用 Invoke 987654327@.

通过在DoWork 中调用 UI 工作,您将面临死锁的风险,这将导致您的程序挂起

【讨论】:

    【解决方案2】:

    你不能在其他线程上运行 UI。必须在主线程上。

    在启动新线程之前实例化 UI。在新线程中,对要使用的控件使用跨线程调用方法。看这里例如http://msdn.microsoft.com/en-us/library/ms171728.aspx

    【讨论】:

    • 除非您要提出实际的解决方案,否则最好将其发布为评论。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多