不创建新的Backgroundworker实例-C#

不创建新的Backgroundworker实例-C#,c#,winforms,C#,Winforms,我正在创建一个利用backgroundworker运行流程的进度表。它在第一次显示表单时运行正常,但是在那之后我得到了错误 其他信息:此操作已完成操作 打电话给它,再打电话是非法的 当我尝试调用BackgroundWorker.ReportProgress()方法时 我很困惑,因为我在块中创建进度表单,如下所示: using (ProgressForm FPProgForm = new ProgressForm(TheUI)) { FPProgForm.ShowDialog();

我正在创建一个利用backgroundworker运行流程的进度表。它在第一次显示表单时运行正常,但是在那之后我得到了错误

其他信息:此操作已完成操作 打电话给它,再打电话是非法的

当我尝试调用
BackgroundWorker.ReportProgress()方法时

我很困惑,因为我在
块中创建进度表单,如下所示:

using (ProgressForm FPProgForm = new ProgressForm(TheUI))
{
    FPProgForm.ShowDialog();    

    if (FPProgForm.DialogResult == DialogResult.OK)
    {
        // display results screen
    }
}
FPProgForm
构造函数中,我正在创建一个新的
BackgroundWorker()

因此,每当我创建一个新对话框时,
BackGroundWorker
应该是全新的

更新:根据请求,以下是整个进度表类:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FPDWF
{
    public partial class ProgressForm : Form
    {

        public delegate void RunFunctionDelegate();

        RunFunctionDelegate FuncToRun { get; }  // function to be run
        FPDesktopWFUI TheUI { get; }
        BackgroundWorker TheBackgroundworker;  // for internal use only, like a viagra demo

        public ProgressForm(RunFunctionDelegate funcToRun, FPDesktopWFUI theUI)
        {
            InitializeComponent();

            FuncToRun = funcToRun;
            TheUI = theUI;

            TheBackgroundworker = new BackgroundWorker();
            InitializeBackgroundWorker();

            // subscription to event stuff here: http://stackoverflow.com/questions/14871238/report-progress-backgroundworker-from-different-class-c-sharp
            TheUI.OnProgressUpdate += FPProgUpdate;
        }

        // Set up the BackgroundWorker object by 
        // attaching event handlers. 
        private void InitializeBackgroundWorker()
        {
            // background worker stuff here: https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx            
            TheBackgroundworker.DoWork +=
                new DoWorkEventHandler(TheBackgroundworker_DoWork);
            TheBackgroundworker.RunWorkerCompleted +=
                new RunWorkerCompletedEventHandler(TheBackgroundworker_RunWorkerCompleted);
            TheBackgroundworker.ProgressChanged +=
                new ProgressChangedEventHandler(TheBackgroundworker_ProgressChanged);

            TheBackgroundworker.WorkerReportsProgress = true;
            TheBackgroundworker.WorkerSupportsCancellation = true;
        }

        private void ProgressForm_Load(object sender, EventArgs e)
        {
            // progress bar stuff here: http://stackoverflow.com/questions/12126889/how-to-use-winforms-progress-bar
            ui_progbar.Maximum = 100;
            ui_progbar.Step = 1;
            ui_progbar.Value = 0;
            TheBackgroundworker.RunWorkerAsync();
        }

        private void ui_cancelbutton_Click(object sender, EventArgs e)
        {
            if (TheBackgroundworker.WorkerSupportsCancellation == true)
            {
                // Cancel the asynchronous operation.
                TheBackgroundworker.CancelAsync();  // there really is no purpose to this as i can just set the contRunning flag I think
                TheUI.contRunning = false; // i think this thread safe due to 'volatile flag', https://msdn.microsoft.com/en-us/library/7a2f3ay4(v=vs.100).aspx                
                resultLabel.Text = "Cancelling...";
            }
        }

        // This event handler is where the time-consuming work is done.
        private void TheBackgroundworker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            FuncToRun();
        }

        // This event handler updates the progress.
        private void TheBackgroundworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // something to do here?
        }

        // This event handler deals with the results of the background operation.
        private void TheBackgroundworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (TheBackgroundworker.CancellationPending == true) // if (e.Cancelled == true)
            {
                this.DialogResult = DialogResult.Cancel;
                this.Close();
            }
            else if (e.Error != null)
            {
                this.DialogResult = DialogResult.Abort;
                resultLabel.Text = "Error: " + e.Error.Message;
                ui_viewres_btn.Text = "Close";
                ui_viewres_btn.Enabled = true;
            }
            else
            {
                this.DialogResult = DialogResult.OK;
                ui_viewres_btn.Enabled = true;
            }

        }

        private void FPProgUpdate(string progText, double prog)
        {
            // utilizing this: http://stackoverflow.com/a/14871753/3661120
            int intProg = Convert.ToInt32(prog * 100);
            if (!TheBackgroundworker.CancellationPending)
            {
                TheBackgroundworker.ReportProgress(intProg);  // doesn't really do anything at this point, but whatev
                base.Invoke((Action)delegate
                {
                    resultLabel.Text = progText;
                    ui_progbar.Value = intProg;
                });
            }
        }

        private void ui_viewres_btn_Click(object sender, EventArgs e)
        {
            this.Close();  // closes the window
        }
    }
}
更新2:即使我删除了有问题的
backgroundworker.ReportProgress(intProg)行,我仍然收到此错误:

其他信息:无法在服务器上调用Invoke或BeginInvoke 控件,直到创建窗口句柄为止


BackgroundWorker.ReportProgress
只能从执行
DoWork
的线程内部调用。从您的代码中,它看起来像是
FPProgUpdate
包含一个
ReportProgress
,并且正在从某个线程调用,而不是从启动
DoWork

BackgroundWorker的线程调用。ReportProgress
只能从执行
DoWork
的线程内部调用。从您的代码中,它看起来像是
FPProgUpdate
包含一个
ReportProgress
,并且正在从启动
DoWork

的线程以外的某个线程调用。您检索此错误是因为您订阅了此事件:

TheUI.OnProgressUpdate += FPProgUpdate;
因此,
FPProgUpdate
多次调用
ReportProgress()

正如您已经注意到的,以下类似项不是必需的,您可以将其删除:

TheBackgroundworker.ReportProgress(intProg);

您检索此错误是因为您正在订阅此事件:

TheUI.OnProgressUpdate += FPProgUpdate;
因此,
FPProgUpdate
多次调用
ReportProgress()

正如您已经注意到的,以下类似项不是必需的,您可以将其删除:

TheBackgroundworker.ReportProgress(intProg);

谢谢马克在这方面的帮助。解决方案是,我需要从处置方法中的ui.on progressupdate
事件中取消订阅
FPProgUpdate
,我必须覆盖该事件:

protected override void Dispose(bool disposing)
        {
            if (disposed)
                return;

            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }

                // Dispose stuff here
                TheUI.OnProgressUpdate -= FPProgUpdate;

            }

            disposed = true;
            base.Dispose(disposing);
        }

处置不会自动取消订阅,看起来是这样。

感谢Marc在这方面的帮助。解决方案是,我需要从处置方法中的ui.on progressupdate
事件中取消订阅
FPProgUpdate
,我必须覆盖该事件:

protected override void Dispose(bool disposing)
        {
            if (disposed)
                return;

            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }

                // Dispose stuff here
                TheUI.OnProgressUpdate -= FPProgUpdate;

            }

            disposed = true;
            base.Dispose(disposing);
        }

处置不会自动取消订阅,这似乎是。

我认为问题出在其他地方。在哪里调用BackgroundWorker.ReportProgress()
?你能出示进度表吗?我想问题出在别的地方。在哪里调用BackgroundWorker.ReportProgress()
?可以显示ProgressForm吗?谢谢,但现在我收到另一条错误消息
附加信息:在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke。
。谢谢,但现在我收到另一条错误消息
附加信息:在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke。
(如下)谢谢,但现在我收到另一条错误消息
附加信息:在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke。
。请尝试在ProgressForm的
显示的
事件中启动BackgroundWorker,而不是
加载
。这似乎太早了。好的,还有一个问题:
TheUI
的实例正在调用FPProgUpdate。这并不像斯科特已经提到的那样好。最好在BackgroundWorkers
ProgressChanged
事件中更新UI(将代码从FPProgUpdate移动到那里)。但是在不知道ui的实现的情况下,我们无法告诉您一个正确的答案……这就是stack overflow post关于过程如何报告其进度的解决方案。还有其他建议吗?无论如何,我不明白为什么表单没有被处理。同样,它在我第一次运行它时仍然有效。感谢您的帮助。(如下)谢谢,但现在我收到另一条错误消息
附加信息:在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke。
。请尝试在ProgressForm的
Showed
事件中启动BackgroundWorker,而不是
Load
。这似乎太早了。好的,还有一个问题:
TheUI
的实例正在调用FPProgUpdate。这并不像斯科特已经提到的那样好。最好在BackgroundWorkers
ProgressChanged
事件中更新UI(将代码从FPProgUpdate移动到那里)。但是在不知道ui的实现的情况下,我们无法告诉您一个正确的答案……这就是stack overflow post关于过程如何报告其进度的解决方案。还有其他建议吗?无论如何,我不明白为什么表单没有被处理。同样,它在我第一次运行它时仍然有效。谢谢你的帮助。