简体   繁体   English

从backgroundworker c#调用的方法内部更新过程

[英]Update process from within method called by backgroundworker c#

I have an application with a gui and a Rich Text Box where i output what the program is currently doing since data processing can be quite long. 我有一个带有gui和Rich Text Box的应用程序,由于数据处理时间很长,我在其中输出程序当前正在执行的操作。

I tried two approaches for that: 为此,我尝试了两种方法:

1 In the Backgroundworker Method I can just call the following code fine: 1在Backgroundworker方法中,我可以很好地调用以下代码:

GlobalVar.backgroundWorkerAppendText = task.Build_CSV_List();
Processchange();

Whereas i cannot use Form1.Processchange(); 而我不能使用Form1.Processchange(); in the helper class due to the non static context 在助手类中由于非静态上下文

2 Therefore I tried to create my very first eventhandler. 2因此,我尝试创建我的第一个事件处理程序。
The Idea was that helper.UpdateConsole() would raise an event 想法是helper.UpdateConsole()会引发一个事件

public event EventHandler OnConsoleUpdate;
public void Consoleupdate()
{
    OnConsoleUpdate(this, EventArgs.Empty);
}

to which the Backgroundworker listens and then calls Processchange from its context Backgroundworker侦听到的对象,然后从其上下文中调用Processchange

public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    StandardTasks task = new StandardTasks();
    Helper helper = new Helper();
    helper.OnConsoleUpdate += Processchange;
    task.DoSomeStuffHere()
}
public void Processchange(object sender=null, EventArgs e=null)
{
    //MessageBox.Show(GlobalVar.backgroundWorkerAppendText);
    GlobalVar.next = false;
    backgroundWorker1.ReportProgress(1);
    while (GlobalVar.next == false)
    {
        helper.TimeBreaker(100,"ms");
    }
}

Unfortunately this was was not successful. 不幸的是,这并不成功。 As soon as rising the Event I get the errormessage System.NullReferenceException which -after googling- leads me to the conclusion that there is no listerner attached to the event eventhouh I attached it in the Backgroundworker Do work. 一旦事件上升,我就会收到errormessage System.NullReferenceException ,它在谷歌搜索之后使我得出结论:事件事件没有附加listerner,但是我将其附加到Backgroundworker中。

Edit: the OnConsoleUpdate() == null as shown on the screenshot below 编辑:OnConsoleUpdate()== null,如下面的屏幕快照所示

event = null 事件=空

The helper is in another class file "helpers" which might be important for a solution. 该帮助程序位于另一个类文件“ helpers”中,这对于解决方案可能很重要。

i hope you guys can help me out. 我希望你们能帮助我。

Welcome to SO! 欢迎来到SO!

A few things immediately jump to mind. 立刻想到了几件事。

First, let's get the event issue out of the way. 首先,让我们解决事件问题。 You've got the correct approach - you need an event and method to call it, but that method should check if the event is null . 您已经找到了正确的方法-您需要一个事件和方法来调用它,但是该方法应该检查事件是否为null

Basically, do this: 基本上,执行以下操作:

public event EventHandler OnConsoleUpdate;
public void ConsoleUpdate()
{
    OnConsoleUpdate?.Invoke(this, EventArgs.Empty);
}

The above makes use of ? 以上利用? , a null-condition operator. ,一个空条件运算符。 You can read more about it on this MSDN page . 您可以在此MSDN页面上阅读有关它的更多信息。

Second thing... it's unclear what your background worker actually IS. 第二件事...目前尚不清楚您的后台工作者实际上是什么。 It sounds like it's some kind of custom class you crated? 听起来这是您创建的某种自定义类? The reason it's important is because .NET actually has a BackgroundWorker class used for running operations... well, in the background. 之所以重要,是因为.NET实际上有一个BackgroundWorker类用于运行操作……嗯,在后台。 It also has an OnProgressChanged event which you can hook up to which could be used to update the UI (just remember to set the WorkerReportsProgress property to true ). 它还有一个OnProgressChanged事件,您可以将其连接到该事件,该事件可用于更新UI(只记得将WorkerReportsProgress属性设置为true )。 And to use the BackgroundWorker mentioned above, you shouldn't need to create any events of your own. 并且要使用上面提到的BackgroundWorker ,您不需要创建自己的事件。

Here's how you can use the standard .NET BackgroundWorker : 这是使用标准.NET BackgroundWorker

System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();

void StartBackgroundTask()
{
    worker.DoWork += worker_DoWork;
    //if it's possible to display progress, use this
    worker.WorkerReportsProgress = true;
    worker.ProgressChanged += worker_ProgressChanged;
    //what to do when the method finishes?
    worker.RunWorkerCompleted += worker_RunWorkerCompleted;
    //start!
    worker.RunWorkerAsync();
}

void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    //perform any "finalization" operations, like re-enable disabled buttons
    //display the result using the data in e.Result
    //this code will be running in the UI thread
}

//example of a container class to pass more data in the ReportProgress event
public class ProgressData
{
    public string OperationDescription { get; set; }
    public int CurrentResult { get; set; }
    //feel free to add more stuff here
}

void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
    //display the progress using e.ProgressPercentage or e.UserState
    //this code will be running in the UI thread
    //UserState can be ANYTHING:
    //var data = (ProgressData)e.UserState;
}

void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    //this code will NOT be running in the UI thread!
    //you should NOT call the UI thread from this method

    int result = 1;
    //perform calculations
    for (var i = 1; i <= 10; i++)
    {
        worker.ReportProgress(i, new ProgressData(){ OperationDescription = "CustomState passed as second, optional parameter", CurrentResult = result });
        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
        result *= i;
    }

    e.Result = result;
}

Now, the thing about the BackgroundWorker class is that it is rather old, and with current .NET versions you can use the async / await keywords to easily handle background operations and UI updates, but this probably is going outside the bounds of this question. 现在,关于BackgroundWorker类的事情是,它已经很老了,在当前的.NET版本中,您可以使用async / await关键字轻松处理后台操作和UI更新,但这可能超出了此问题的范围。 That said, the existence of async / await doesn't invalidate the use of BackgroundWorker which is pretty simple in its usage. 也就是说, async / await的存在不会使BackgroundWorker的使用无效,这在其用法上非常简单。

There's one more worrisome thing in your code. 您的代码中还有另外一件令人担忧的事情。

public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    StandardTasks task = new StandardTasks(); //<- you create a task
    Helper helper = new Helper(); // <- you create a helper
    helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper event
    task.DoSomeStuffHere(); // <- you do stuff with the task... but the task doesn't know about your helper above! Does `StandardTasks` use `Helper`? If so, how?
}

Do note that events, unless made static , aren't global. 请注意,除非将事件设为static ,否则事件不是全局事件。 So hooking up to an event in one instance of a class won't cause another instance of that class to "fire" that event. 因此,在一个类的一个实例中挂接到事件将不会导致该类的另一个实例“触发”该事件。 It seems one way to fix your issues would be to make the StandardTasks class take Helper as one of the constructor parameters, so the code would look like this: 解决问题的一种方法似乎是使StandardTasks类将Helper用作构造函数参数之一,因此代码如下所示:

Helper helper = new Helper(); // <- you create a helper
helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper class event to actually do something
StandardTasks task = new StandardTasks(helper); //<- you create a task which will use the helper with the hooked up event above

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM