从 backgroundworker c# 调用的方法中更新进程
Update process from within method called by backgroundworker c#
我有一个带有 gui 和 Rich Text Box
的应用程序,我在其中输出程序当前正在执行的操作,因为数据处理可能会很长。
为此我尝试了两种方法:
1 在 Backgroundworker 方法中,我可以调用以下代码:
GlobalVar.backgroundWorkerAppendText = task.Build_CSV_List();
Processchange();
而由于非静态上下文
,我无法在助手 class 中使用 Form1.Processchange();
2 因此,我尝试创建我的第一个事件处理程序。
这个想法是 helper.UpdateConsole() 会引发一个事件
public event EventHandler OnConsoleUpdate;
public void Consoleupdate()
{
OnConsoleUpdate(this, EventArgs.Empty);
}
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");
}
}
不幸的是,这没有成功。一旦事件发生,我就会收到错误消息 System.NullReferenceException
,在谷歌搜索后,我得出的结论是事件没有附加任何侦听器 eventhouh 我在 Backgroundworker 中附加了它。
编辑:OnConsoleUpdate() == null,如下面的屏幕截图所示
event = null
助手在另一个 class 文件“助手”中,这可能对解决方案很重要。
希望大家帮帮我。
欢迎来到 SO!
有几件事立即跳入脑海。
首先,让我们解决事件问题。你有正确的方法 - 你需要一个事件和方法来调用它,但该方法应该检查事件是否为 null
.
基本上,这样做:
public event EventHandler OnConsoleUpdate;
public void ConsoleUpdate()
{
OnConsoleUpdate?.Invoke(this, EventArgs.Empty);
}
上面使用了空条件运算符?
。您可以阅读更多相关信息 on this MSDN page。
第二件事...不清楚您的后台工作人员到底是什么。听起来像是您创建的某种习俗 class?它之所以重要,是因为 .NET 实际上有一个 BackgroundWorker
class 用于 运行 操作……好吧,在后台。它还有一个 OnProgressChanged
事件,您可以连接到该事件可用于更新 UI (只记得将 WorkerReportsProgress
属性 设置为 true
).要使用上面提到的 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;
}
现在,关于 BackgroundWorker
class 的问题是它相当陈旧,对于当前的 .NET 版本,您可以使用 async / await
关键字轻松处理后台操作和UI 更新,但这可能超出了这个问题的范围。也就是说,async / await
的存在不会使 BackgroundWorker
的使用无效,它的用法非常简单。
您的代码中还有一件令人担忧的事情。
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?
}
请注意,除非static
,否则事件不是全球性的。因此,在 class 的一个实例中连接到一个事件不会导致该 class 的另一个实例到 "fire" 该事件。似乎解决问题的一种方法是使 StandardTasks
class 将 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
我有一个带有 gui 和 Rich Text Box
的应用程序,我在其中输出程序当前正在执行的操作,因为数据处理可能会很长。
为此我尝试了两种方法:
1 在 Backgroundworker 方法中,我可以调用以下代码:
GlobalVar.backgroundWorkerAppendText = task.Build_CSV_List();
Processchange();
而由于非静态上下文
,我无法在助手 class 中使用Form1.Processchange();
2 因此,我尝试创建我的第一个事件处理程序。
这个想法是 helper.UpdateConsole() 会引发一个事件
public event EventHandler OnConsoleUpdate;
public void Consoleupdate()
{
OnConsoleUpdate(this, EventArgs.Empty);
}
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");
}
}
不幸的是,这没有成功。一旦事件发生,我就会收到错误消息 System.NullReferenceException
,在谷歌搜索后,我得出的结论是事件没有附加任何侦听器 eventhouh 我在 Backgroundworker 中附加了它。
编辑:OnConsoleUpdate() == null,如下面的屏幕截图所示
event = null
助手在另一个 class 文件“助手”中,这可能对解决方案很重要。
希望大家帮帮我。
欢迎来到 SO!
有几件事立即跳入脑海。
首先,让我们解决事件问题。你有正确的方法 - 你需要一个事件和方法来调用它,但该方法应该检查事件是否为 null
.
基本上,这样做:
public event EventHandler OnConsoleUpdate;
public void ConsoleUpdate()
{
OnConsoleUpdate?.Invoke(this, EventArgs.Empty);
}
上面使用了空条件运算符?
。您可以阅读更多相关信息 on this MSDN page。
第二件事...不清楚您的后台工作人员到底是什么。听起来像是您创建的某种习俗 class?它之所以重要,是因为 .NET 实际上有一个 BackgroundWorker
class 用于 运行 操作……好吧,在后台。它还有一个 OnProgressChanged
事件,您可以连接到该事件可用于更新 UI (只记得将 WorkerReportsProgress
属性 设置为 true
).要使用上面提到的 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;
}
现在,关于 BackgroundWorker
class 的问题是它相当陈旧,对于当前的 .NET 版本,您可以使用 async / await
关键字轻松处理后台操作和UI 更新,但这可能超出了这个问题的范围。也就是说,async / await
的存在不会使 BackgroundWorker
的使用无效,它的用法非常简单。
您的代码中还有一件令人担忧的事情。
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?
}
请注意,除非static
,否则事件不是全球性的。因此,在 class 的一个实例中连接到一个事件不会导致该 class 的另一个实例到 "fire" 该事件。似乎解决问题的一种方法是使 StandardTasks
class 将 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