Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从BackgroundWorker处理表单_C#_Winforms_Backgroundworker - Fatal编程技术网

C# 从BackgroundWorker处理表单

C# 从BackgroundWorker处理表单,c#,winforms,backgroundworker,C#,Winforms,Backgroundworker,我有一个主窗口(form1)和一个名为Module的类 在模块中,有一种方法可以创建新的Backgroundworker并在主窗口中更改标签。我曾尝试在主窗口代码中创建一个公共或内部方法,并在模块类中调用它,但它似乎不起作用 谁能帮我弄明白,这只是阻止我继续发展的原因 对不起,如果我没有说清楚,如果你需要澄清,请告诉我 模块.cs public class Module { protected System.Diagnostics.PerformanceCounter cpuCounte

我有一个主窗口(form1)和一个名为Module的类

在模块中,有一种方法可以创建新的Backgroundworker并在主窗口中更改标签。我曾尝试在主窗口代码中创建一个公共或内部方法,并在模块类中调用它,但它似乎不起作用

谁能帮我弄明白,这只是阻止我继续发展的原因

对不起,如果我没有说清楚,如果你需要澄清,请告诉我

模块.cs

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";
    }
}