从BackgroundWorker操作表单

发布于 2024-09-17 19:11:36 字数 1765 浏览 2 评论 0原文

我有一个 MainWindow (form1) 和一个名为 Module 的类

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

谁能帮我解决这个问题,这只是阻止我继续发展的原因。

抱歉,如果我没有说清楚,如果您需要澄清一些事情,请告诉我。

Module.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();
    }
}

MainWindow - 包含标签 (labelCPUU)

internal void changeCPUULabel(string val)
    {
        Dispatcher.Invoke(new UIDelegate(delegate
            {
                this.labelCPUU.Content = val;
            }));
    }
public double getCurrentCpuUsage()
    {
       return mod.getCurrentCpuUsage();
    }
void activateCPUU(){ mod.runCPUUsage(); }

I have a MainWindow (form1) and a class called Module

In Module there is a method to create a new Backgroundworker and change a label in MainWindow. I have tried creating a public or internal method in the MainWindow code and calling it in the Module class but it doesn't seem to work.

Can anyone help me figure this out, it's just something which is stopping me from continuing development.

Sorry if I didn't make things clear, if you need something cleared up let me know.

Module.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();
    }
}

MainWindow - Contains a label (labelCPUU)

internal void changeCPUULabel(string val)
    {
        Dispatcher.Invoke(new UIDelegate(delegate
            {
                this.labelCPUU.Content = val;
            }));
    }
public double getCurrentCpuUsage()
    {
       return mod.getCurrentCpuUsage();
    }
void activateCPUU(){ mod.runCPUUsage(); }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

他夏了夏天 2024-09-24 19:11:36

您是否尝试从与 GUI 线程不同的线程更改标签?你不能那样做。但是,您可以在任何控件上调用 Invoke,当 GUI 线程到达该控件时,它将被执行(当然,如果 GUI 线程空闲,则立即执行):

// Instead of:
myMainForm.MyLabel.Text = "New Text";

// Write:
myMainForm.Invoke(new Action(() => { myMainForm.MyLabel.Text = "New Text"; }));

Are you trying to change the label from a different thread than the GUI thread? You can’t do that. You can, however, call Invoke on any control, and it will be executed when the GUI thread gets around to it (which is, of course, immediate if the GUI thread is idle):

// Instead of:
myMainForm.MyLabel.Text = "New Text";

// Write:
myMainForm.Invoke(new Action(() => { myMainForm.MyLabel.Text = "New Text"; }));
泪冰清 2024-09-24 19:11:36

如果您必须使用后台工作程序更新 UI,请使用 ReportProgress 方法。这将触发您应该处理的事件。在那里实现您的 UI 更新逻辑。

If you have to update the UI with the background worker, use the ReportProgress method. That will fire an event that you should handle. Implement your UI update logic there.

﹎☆浅夏丿初晴 2024-09-24 19:11:36

最好不要将表单与模块紧密耦合。一种方法是定义表单实现的接口,并让模块接受这样的接口作为参数。我将用一些代码来举例说明。让我们从界面开始:

public interface IDataReceiver
{
    void SetData(string data);
}

在我的示例中,我使用 string 作为数据,但这可以是您需要使用的任何类型。然后我们以下面的形式实现这个接口:

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

这样模块就不会依赖于你的表单类的样子(它甚至不知道它正在与表单对话)。在我的示例中,我从 RunWorkerCompleted 事件处理程序调用 _receiver.SetData,但也可以从 ReportProgress 事件处理程序完成。

另请注意,形式在这里是如何成为“驱动力”的。该模块不创建表单,也不采取任何类型的举措。它只是由表单使用。

It's a good idea not to couple the form to tightly with the module. One way to do that is to define an interface that the form implements, and have the module accept such an interface as a parameter. I'll exemplify with some code. Let's start with the interface:

public interface IDataReceiver
{
    void SetData(string data);
}

In my example I use a string for the data, but that can be whatever type you need to use. Then we implement this interface in the form:

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
}

Finally the module with the 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";
    }
}

This way the module is in no way depending on what your form class looks like (it is even unaware that it is talking to a form). In my sample I call _receiver.SetData from the RunWorkerCompleted event handler, but it could just as well be done from a ReportProgress event handler.

Also note how the form is the "driving force" here. The module does not create the form, or take any initiatives of any kind. It is simply used by the form.

北音执念 2024-09-24 19:11:36

如果您要在另一个线程(而不是主 UI 线程)中更新 UI,则需要使用 Control.Invoke

If you're updating the UI in another thread (not the main UI thread), you need to use Control.Invoke.

情栀口红 2024-09-24 19:11:36

您是否尝试过在主窗口中它调用的方法上以及后台工作程序中进行调用的代码行上放置一个调试点以查看是否已进行调用?
如果它击中了backgroundworker但没有击中mainwindow,那么backgroundworker可能正在引用它自己的mainwindow版本,而不是您期望的版本?

另一个想法,但对我来说不是一个强项,但他在使用 GUI 线程时遇到了问题。我想知道您的后台工作人员是否位于与 GUI 不同的线程上,这会导致问题。 GUI 应该始终位于其自己的线程上,GUI 中的 sence 代码可能会锁定 GUI。
如果您需要在不同线程之间进行交互,则需要查找调用。

Have you tried putting a debug point in mainwindow on the method it calls, and on the line of code in backgroundworker that makes the call to see if it is even been made?
If it hits backgrounderworker but not mainwindow, it maybe that backgroundworker is referencing its own version of mainwindow not the one you are expecting?

Another idea, but not a strong point for me, but he had an issue at work with GUI threads. Im wondering if your background worker is on a different thread to the GUI adn this is causing issues. The GUI should always be on its own thread, sence code in a GUI can lock up the GUI.
If you need to interact between different thread you need to look up invoking.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文