2010-09-03 55 views
2

操纵形式I具有主窗口(Form1中)和一类称为模块从一个BackgroundWorker

在模块有创建一个新的BackgroundWorker和在主窗口更改标签的方法。我曾尝试在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(); 
    } 
} 

主窗口 - 包含一个标签(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(); } 
+0

从主窗口或模块的一些cample代码可能会有所帮助。 – 2010-09-03 18:05:58

+0

请说明“似乎不起作用”。编译错误?运行时错误?意外的行为? – Bob 2010-09-03 18:07:20

+0

什么不工作?它抛出错误还是你没有看到改变?而像史蒂夫说,某些源将是不错 – 2010-09-03 18:07:44

回答

0

不要将表单与模块紧密结合,这是个好主意。一种方法是定义表单实现的接口,并让模块接受这样的接口作为参数。我将以一些代码为例。让我们先从界面:

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事件处理完成。

还要注意形式是怎样的“推动力”在这里。该模块不会创建表单,也不会采取任何形式的举措。它只是由表单使用。

+0

我已经实现了代码的一部分,它似乎工作得很好,但是当把e.Result =“data”放入while(true)循环中时,它不会更改数据,我需要不断更新数据。 – 2010-09-03 18:36:22

+1

@Sandeep:正如Fredrik所说,您可以使用ReportProgress在工作人员执行时报告进度。你的原始代码有一个'MainWindow',它创建一个'Module',它创建*另一个*'MainWindow'。您的代码*是*更新标签,但是它更新*不同*'MainWindow'的标签 - 而不是屏幕上显示的标签。紧密耦合和糟糕的设计是你问题的根源。 – 2010-09-03 18:58:45

+0

@Sandeep:查看更新的代码示例(仅更改了“SomeModule”)。具体来说,我在构造函数中添加了_worker.WorkerReportsProgress = true;'ProgressChanged'事件的事件处理函数和一个调用ReportProgress的循环。 – 2010-09-03 19:05:06

6

你是不是想标签从不同的线程比GUI线程改变?你不能那样做。你可以,但是,请拨打Invoke上的任何控制,而当GUI线程得到解决它就会被执行(这是当然的,立即如果GUI线程空闲):

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

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

[?所以]从我的螺纹 – 2010-09-03 18:20:35

+0

(http://meta.stackexchange.com/questions/700/) – Timwi 2010-09-03 18:34:23

+0

这似乎并没有被改变任何东西,看看上面我的代码 – 2010-09-03 18:37:26

5

如果你有要使用后台工作人员更新UI,请使用ReportProgress方法。这将激发你应该处理的事件。在那里实现你的UI更新逻辑。

+0

+1 - OP还需要指定ReportProgress =真;当BackgroundWorker的实例化 – 2010-09-03 18:12:31

+0

cpuUThread.WorkerReportsProgress = TRUE;无变化 – 2010-09-03 18:20:17

+0

它不是足够多,你有没有为事件创建ReportProgress事件处理程序,并移动UI更新逻辑 – 2010-09-03 18:37:16

0

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

+0

我使用Dispatcher.Invoke已经 – 2010-09-03 18:19:50

0

您是否曾尝试在mainwindow中调用它的调试方法,并在backgroundworker中的代码行中调用以查看它是否被制作? 如果它碰到backgrounderworker而不是mainwindow,那么背景工作者可能会引用它自己的mainwindow版本,而不是你期望的版本?

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

+0

啊,所以援引是原因。我很惊讶我记得那个。 – JonWillis 2010-09-03 18:10:52

+0

我正在调用线程中的内容给gui。 – 2010-09-03 18:19:16

相关问题