C# 从BackgroundWorker处理表单
我有一个主窗口(form1)和一个名为Module的类 在模块中,有一种方法可以创建新的Backgroundworker并在主窗口中更改标签。我曾尝试在主窗口代码中创建一个公共或内部方法,并在模块类中调用它,但它似乎不起作用 谁能帮我弄明白,这只是阻止我继续发展的原因 对不起,如果我没有说清楚,如果你需要澄清,请告诉我 模块.csC# 从BackgroundWorker处理表单,c#,winforms,backgroundworker,C#,Winforms,Backgroundworker,我有一个主窗口(form1)和一个名为Module的类 在模块中,有一种方法可以创建新的Backgroundworker并在主窗口中更改标签。我曾尝试在主窗口代码中创建一个公共或内部方法,并在模块类中调用它,但它似乎不起作用 谁能帮我弄明白,这只是阻止我继续发展的原因 对不起,如果我没有说清楚,如果你需要澄清,请告诉我 模块.cs public class Module { protected System.Diagnostics.PerformanceCounter cpuCounte
public class Module
{
protected System.Diagnostics.PerformanceCounter cpuCounter;
BackgroundWorker cpuUThread;
private delegate void UIDelegate();
MainWindow mn;
public void runCPUUsage()
{
cpuUThread = new BackgroundWorker();
cpuUThread.DoWork += new DoWorkEventHandler(cpuUThread_DoWork);
cpuUThread.WorkerSupportsCancellation = true;
cpuUThread.RunWorkerAsync();
mn = new MainWindow();
}
void cpuUThread_DoWork(object sender, DoWorkEventArgs e)
{
cpuCounter = new System.Diagnostics.PerformanceCounter();
cpuCounter.CategoryName = "Processor";
cpuCounter.CounterName = "% Processor Time";
cpuCounter.InstanceName = "_Total";
try
{
mn.changeCPUULabel(getCurrentCpuUsage().ToString());
}
catch (Exception ex)
{
}
}
public double getCurrentCpuUsage()
{
return Math.Round(cpuCounter.NextValue(), 0);
}
public void disposeCpuUsage()
{
cpuUThread.CancelAsync();
cpuUThread.Dispose();
}
}
主窗口-包含标签(labelCPUU)
您是否尝试从不同于GUI线程的线程更改标签?你不能那样做。但是,您可以在任何控件上调用
Invoke
,当GUI线程到达该控件时,它将被执行(当然,如果GUI线程空闲,这将立即执行):
如果必须使用后台工作程序更新UI,请使用
ReportProgress
方法。这将触发您应该处理的事件。在那里实现您的UI更新逻辑。如果您在另一个线程(而不是主UI线程)中更新UI,您需要使用控件。调用您是否尝试过在mainwindow中调用的方法上,以及在backgroundworker中进行调用的代码行上放置调试点,以查看是否已进行调试?
如果它点击的是backgrounderworker而不是mainwindow,那么可能backgroundworker引用的是它自己的mainwindow版本,而不是您期望的版本
另一个想法,但不是我的强项,但他在使用GUI线程时遇到了一个问题。我想知道你的后台工作人员是否在GUI的不同线程上,这会导致问题。GUI应该始终在自己的线程上,GUI中的代码可能会锁定GUI。
如果需要在不同线程之间进行交互,则需要查找调用。最好不要将表单与模块紧密耦合。一种方法是定义表单实现的接口,并让模块接受这样的接口作为参数。我将用一些代码来举例说明。让我们从界面开始:
public interface IDataReceiver
{
void SetData(string data);
}
在我的示例中,我对数据使用了字符串
,但它可以是您需要使用的任何类型。然后,我们以以下形式实现此接口:
public partial class Form1 : Form, IDataReceiver
{
private void Button_Click(object sender, EventArgs e)
{
// create a module intstance, passing this form as parameter
var module = new SomeModule(this);
module.DoSomeWork();
}
public void SetData(string data)
{
// use the data that is received
txtSomeTextBox.Text = data;
}
// the rest of the form code left out to keep it short
}
最后,与BackgroundWorker的模块:
public class SomeModule
{
private BackgroundWorker _worker = new BackgroundWorker();
private IDataReceiver _receiver;
public SomeModule(IDataReceiver receiver)
{
_worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);
_worker.ProgressChanged += new ProgressChangedEventHandler(Worker_ProgressChanged);
_worker.WorkerReportsProgress = true;
_receiver = receiver;
}
void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
_receiver.SetData(e.UserState.ToString());
}
public void DoSomeWork()
{
// start the worker
_worker.RunWorkerAsync();
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// call method to pass data to receiver
_receiver.SetData(e.Result.ToString());
}
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
// do some work here
// assign the resulting data to e.Result
for (int i = 0; i < 10; i++)
{
_worker.ReportProgress(0, "some data " + i);
Thread.Sleep(250);
}
e.Result = "Finished";
}
}
公共类模块
{
私人后台工作人员_worker=新后台工作人员();
私人IDataReceiver(接收器);;
公用模块(IDataReceiver接收器)
{
_worker.DoWork+=新的doworkereventhandler(worker\u DoWork);
_worker.RunWorkerCompleted+=新的RunWorkerCompletedEventHandler(worker\u RunWorkerCompleted);
_worker.ProgressChanged+=新的progresschangedventhadler(worker\u ProgressChanged);
_worker.WorkerReportsProgress=true;
_接收器=接收器;
}
void Worker\u ProgressChanged(对象发送方,ProgressChangedEventArgs e)
{
_receiver.SetData(例如UserState.ToString());
}
公共工程
{
//启动工人
_worker.RunWorkerAsync();
}
私有void Worker\u RunWorkerCompleted(对象发送方,RunWorkerCompletedEventArgs e)
{
//调用方法将数据传递给接收方
_receiver.SetData(例如Result.ToString());
}
私有void Worker_DoWork(对象发送方,DoWorkEventArgs e)
{
//在这里做些工作
//将结果数据分配给e.Result
对于(int i=0;i<10;i++)
{
_worker.ReportProgress(0,“部分数据”+i);
睡眠(250);
}
e、 结果=“完成”;
}
}
通过这种方式,模块完全不依赖于表单类的外观(它甚至不知道它正在与表单对话)。在我的示例中,我从RunWorkerCompleted
事件处理程序调用\u receiver.SetData
,但也可以从ReportProgress
事件处理程序调用
还要注意表单是如何成为这里的“驱动力”的。该模块不会创建表单,也不会采取任何形式的主动行动。表单仅使用它。主窗口或模块中的一些cample代码可能会有所帮助。请澄清“似乎不起作用”。编译错误?运行时错误?意外行为?到底是什么不起作用?它是在抛出错误,还是你根本看不到变化?正如Steve所说,如果我在上面添加了代码,那么一些源代码会更好,当我运行activatecpuu()时,窗口会再次创建并显示mn.changecpuulable中的值(…啊,调用就是原因。呵呵,我很惊讶我记得。+1-OP还需要指定ReportProgress=true;当BackgroundWorker被实例化时。这还不够,你必须为事件ReportProgress创建一个事件处理程序,并将UI更新逻辑移到那里。我已经在中实现了你的部分代码,它似乎可以在但将e.Result=“data”放入一段时间后(true)循环它不会更改数据,我需要不断更新数据。@Sandeep:正如Fredrik所说,您可以使用ReportProgress在工作人员执行时报告进度。您的原始代码有一个MainWindow
,它创建了一个模块,该模块创建了另一个MainWindow
。您的代码正在更新标签,但它是更新的ng另一个主窗口的标签
-不是屏幕上显示的标签。紧耦合和不良设计是问题的根源。@Sandeep:请参阅更新的代码示例(仅SomeModule
发生了更改)具体来说,我在构造函数中添加了\u worker.WorkerReportsProgress=true;
,一个用于ProgressChanged
事件的事件处理程序和一个调用ReportProgress
的循环。效果非常好,Fredrik,非常感谢。@Kent感谢您提供的关于糟糕设计的信息,我正在重新构建我的代码等。它似乎没有若要更改任何内容,请查看上面的代码。
public partial class Form1 : Form, IDataReceiver
{
private void Button_Click(object sender, EventArgs e)
{
// create a module intstance, passing this form as parameter
var module = new SomeModule(this);
module.DoSomeWork();
}
public void SetData(string data)
{
// use the data that is received
txtSomeTextBox.Text = data;
}
// the rest of the form code left out to keep it short
}
public class SomeModule
{
private BackgroundWorker _worker = new BackgroundWorker();
private IDataReceiver _receiver;
public SomeModule(IDataReceiver receiver)
{
_worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);
_worker.ProgressChanged += new ProgressChangedEventHandler(Worker_ProgressChanged);
_worker.WorkerReportsProgress = true;
_receiver = receiver;
}
void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
_receiver.SetData(e.UserState.ToString());
}
public void DoSomeWork()
{
// start the worker
_worker.RunWorkerAsync();
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// call method to pass data to receiver
_receiver.SetData(e.Result.ToString());
}
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
// do some work here
// assign the resulting data to e.Result
for (int i = 0; i < 10; i++)
{
_worker.ReportProgress(0, "some data " + i);
Thread.Sleep(250);
}
e.Result = "Finished";
}
}