Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.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#GUI类如何从工人类接收定期更新?_C#_Multithreading_User Interface - Fatal编程技术网

C#GUI类如何从工人类接收定期更新?

C#GUI类如何从工人类接收定期更新?,c#,multithreading,user-interface,C#,Multithreading,User Interface,我试图将我的工作代码从GUI代码分离到一个完全不同的类中,但我希望能够向GUI报告进度更新和文件输出。例如,我想让我的GUI对worker类说,“从串行端口读取十行,但在接收到它时向我报告您读取的每一行”。目前,我最好的方法是让GUI循环十次,然后在每个循环中向worker类发送一个命令,以读取一个内容并返回它 我真的希望将所有的循环都放在我的工人类的一边,因为它将有更多关于可用数据的信息(实际数据量将是可变的,工人类已经可以访问可用数据量,我不希望将其发送回GUI类来运行循环本身 我已经调查了

我试图将我的工作代码从GUI代码分离到一个完全不同的类中,但我希望能够向GUI报告进度更新和文件输出。例如,我想让我的GUI对worker类说,“从串行端口读取十行,但在接收到它时向我报告您读取的每一行”。目前,我最好的方法是让GUI循环十次,然后在每个循环中向worker类发送一个命令,以读取一个内容并返回它

我真的希望将所有的循环都放在我的工人类的一边,因为它将有更多关于可用数据的信息(实际数据量将是可变的,工人类已经可以访问可用数据量,我不希望将其发送回GUI类来运行循环本身

我已经调查了backgroundworker,但这似乎只报告了在一次长时间的操作中完成的百分比,而没有其他内容,所以这对我没有多大帮助。有人知道我如何完成这项工作吗

下面是一个程序的外壳,试图(希望)更好地说明我想做什么。你会如何编辑代码来完成我的要求

GUI的主类:

class Main_Class
{
    ...
    /*  Assume in the area we have instantiated these items and placed them on the form:
    *   Button  DoSomething:  A button to do something
    *   TextBox ShowInfo:  A text box to report something from the worker class     
    */

    Worker_Class timewaster = new Worker_Class();

    private void buttonDoSomething_Click(object sender, EventArgs e)
    {
        timewaster.a_lengthy_task();
    }
}
独立工人阶级:

class Worker_Class
{
    ...//Various Setup stuff up here

    void a_lengthy task()
    {
        int iteration = 0;

        while(iteration < 10)
        {
            Datetime saveNOW = Datetime.Now;        //lets say I report this back to the the GUI to write in that ShowInfo box
            Thread.sleep(10000);                    //To waste time and make this lengthy

            //Your code here to facilitate sending saveNOW back to the the Main_Class and display it on the ShowInfo textbox.

            iteration++
        }
    }
}
public class Worker_Class
{
    //Various Setup stuff up here

    public class IterationEventArgs : EventArgs
    {
        public string iterationNumber { get; set; }
    }

    public event EventHandler<IterationEventArgs> IterationComplete;

    public void LengthyTask()
    {
        int iteration = 0;

        while (iteration < 10)
        {
            DateTime saveNOW = DateTime.Now;        //lets say I report this back to the the GUI to write in that ShowInfo box
            Thread.Sleep(10000);                    //To waste time and make this lengthy

            //Your code here to facilitate sending saveNOW back to the the Main_Class and display it on the ShowInfo textbox.

            if (IterationComplete != null)
            {
                IterationEventArgs args = new IterationEventArgs();
                args.iterationNumber = iteration.ToString();
                IterationComplete(this, args);
            }

            iteration++;
        }
    }
}
class Worker\u class
{
…//这里有各种各样的设置
作废一项冗长的任务()
{
int迭代=0;
而(迭代<10次)
{
Datetime saveNOW=Datetime.Now;//假设我将此报告回GUI,并在该ShowInfo框中写入
Thread.sleep(10000);//浪费时间并使其冗长
//您可以在此处输入代码,以便将saveNOW发送回主类并在ShowInfo文本框中显示。
迭代++
}
}
}

您需要的是事件。如果您无法绕过
BackgroundWorker
类中内置的内容来让它为您工作,那么您至少可以根据它的功能对解决方案进行建模

worker类应该有一个公共事件
IterationComplete
或您想调用的任何东西。您可以给它一个
EventArgs
对象(或扩展EventArgs的对象),该对象包含UI将需要的与该迭代相关的信息。可以在每次迭代完成后激发该事件(或在需要修改UI时)

然后,UI可以订阅与该迭代相关的所有UI任务的事件

代码示例:

主要类别:

public class MainClass
{
    Worker_Class timewaster = new Worker_Class();


    private void buttonDoSomething_Click(object sender, EventArgs e)
    {
        timewaster.IterationComplete += new EventHandler<Worker_Class.IterationEventArgs>(timewaster_IterationComplete);
        timewaster.LengthyTask();
    }

    void timewaster_IterationComplete(object sender, Worker_Class.IterationEventArgs e)
    {
        string infoFromWorker = e.iterationNumber;
    }
}
public类MainClass
{
Worker_Class timewaster=新的Worker_Class();
私有无效按钮单击(对象发送者,事件参数e)
{
timewaster.IterationComplete+=新事件处理程序(timewaster\u IterationComplete);
浪费时间。长度任务();
}
void timewaster_IterationComplete(对象发送方,Worker_Class.IterationEventArgs e)
{
字符串infoFromWorker=e.iterationNumber;
}
}
工人阶级:

class Worker_Class
{
    ...//Various Setup stuff up here

    void a_lengthy task()
    {
        int iteration = 0;

        while(iteration < 10)
        {
            Datetime saveNOW = Datetime.Now;        //lets say I report this back to the the GUI to write in that ShowInfo box
            Thread.sleep(10000);                    //To waste time and make this lengthy

            //Your code here to facilitate sending saveNOW back to the the Main_Class and display it on the ShowInfo textbox.

            iteration++
        }
    }
}
public class Worker_Class
{
    //Various Setup stuff up here

    public class IterationEventArgs : EventArgs
    {
        public string iterationNumber { get; set; }
    }

    public event EventHandler<IterationEventArgs> IterationComplete;

    public void LengthyTask()
    {
        int iteration = 0;

        while (iteration < 10)
        {
            DateTime saveNOW = DateTime.Now;        //lets say I report this back to the the GUI to write in that ShowInfo box
            Thread.Sleep(10000);                    //To waste time and make this lengthy

            //Your code here to facilitate sending saveNOW back to the the Main_Class and display it on the ShowInfo textbox.

            if (IterationComplete != null)
            {
                IterationEventArgs args = new IterationEventArgs();
                args.iterationNumber = iteration.ToString();
                IterationComplete(this, args);
            }

            iteration++;
        }
    }
}
public class Worker\u class
{
//这里有各种各样的设置
公共类IterationEventArgs:EventArgs
{
公共字符串迭代编号{get;set;}
}
公共事件事件处理程序迭代完成;
公共无效长度任务()
{
int迭代=0;
而(迭代<10次)
{
DateTime saveNOW=DateTime.Now;//假设我将此报告回GUI,并在该ShowInfo框中写入
Thread.Sleep(10000);//浪费时间并使其冗长
//您可以在此处输入代码,以便将saveNOW发送回主类并在ShowInfo文本框中显示。
if(IterationComplete!=null)
{
IterationEventArgs args=新的IterationEventArgs();
args.iterationNumber=iteration.ToString();
迭代完成(此参数为args);
}
迭代++;
}
}
}

在我的后台工作程序中,我使用:

this.Invoke((MethodInvoker)delegate
{
    //do something in GUI
});
例如,如果要更改GUI中的标签,请使用

label.Text = "whatever";

方法内部。

这是
BackgroundWorker
类的理想任务。假设您不使用紧凑框架,它应该可以供您使用

BackgroundWorker
上,您可以收听
onCompleted
onProgressUpdated
事件。这些事件为您编组到UI线程中,您可以使用它们安全地更新winform/wpf控件。要显示进度,请在
DoWork()中调用
ReportProgress()
后台工作人员的

将代码放入单独的线程时,更新GUI控件时需要小心。更新控件的线程必须是UI线程。BackgroundWorker会为您处理此问题


MSDN-

您需要让您的
工作者类通过事件广播其进度。
主类将订阅此事件并使用信息相应地更新UI。您可以从这里分为两个方向。您可以使用
控件。调用
将此事件处理程序封送到UI上线程,您可以在其中安全地更新GUI。或者您可以让事件处理程序将进度信息保存到共享变量。然后让您的UI通过
System.Windows.Forms.Timer
Dispatcher
在方便的时间间隔内轮询此变量。在这种情况下,我更喜欢后面的方法

class YourForm : Form
{
  private volatile MyEventArgs progress = null;

  private void buttonDoSomething_Click(object sender, EventArgs args)
  {
    var timewaster = new Worker_Class();
    timewaster.ProgressChanged += (sender, args) { progress = args; };
    Task.Factory.StartNew(
      () =>
      {
        timewaster.a_lengthy_task();
      }
    UpdateTimer.Enabled = true;
  }

  private void UpdateTimer_Tick(object sender, EventArgs args)
  {
    if (progress != null)
    {
      if (progress.IsFinished)
      {
        ShowInfo.Text = "Finished";
        UpdateTimer.Enabled = false;
      }
      else
      {
        ShowInfo.Text = progress.SaveNow.Value.ToString();
      }
    }
    else
    {
      ShowInfo.Text = "No progress yet";
    }
  }
}

class Worker_Class
{
  public event EventHandler<MyEventArgs> ProgressChanged;

  public Worker_Class()
  {
    ProgressChanged += (sender, args) => { };
  }

  public void a_lengthy task()
  {
    int iteration = 0;
    while(iteration < 10)
    {
        Datetime saveNOW = Datetime.Now;
        Thread.sleep(10000);
        ProgressChanged(this, new MyEventArgs { SaveNow = saveNOW, IsFinished = false });
        iteration++
    }
    ProgressChanged(this, new MyEventArgs { SaveNow = null, IsFinished = true });
  }
}

class MyEventArgs : EventArgs
{
  public DateTime? SaveNow { get; set; }
  public bool IsFinished { get; set; }
}
class-YourForm:Form
{
private volatile MyEventArgs progress=null;
私有无效按钮单击(对象发送者、事件args args)
{
var timewaster=new Worker_Class();
timewaster.ProgressChanged+=(发送方,args){progress=args;};
Task.Factory.StartNew(
() =>
{
浪费时间。一项冗长的任务();
}
UpdateTimer.Enabled=true;
}
私有无效更新