如何将单个事件从线程传递到GUI表单线程?

时间:2013-01-02 17:31:14

标签: c# multithreading

我是C#的新手,并且无法弄清楚如何将事件从线程传递到GUI表单线程。任何帮助,将不胜感激。我发现的所有例子都太复杂了。我只想从处理GUI的一个事件开始,让GUI做一些事情(现在,任何事情)。

namespace testEvents
{
public delegate void StuffHappenedDel( MessageEventArgs e);

public partial class Form1 : Form
{


    workerThread thread;
    int j = 0;
    public Form1()
    {
        InitializeComponent();
        thread = new workerThread();
        thread.Start();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        thread.Stop();
    }



    private void StuffHappenedDel(Object seder, EventArgs e)
    {
        j++;
    }


}

public class workerThread
{
    Thread worker;
    private bool _quit = false;

    /*  I don't think this next line is correct*/
    public event StuffHappenedDel StuffHappened;


    protected virtual void OnStuffHappened(MessageEventArgs e)
    {
        if (StuffHappened != null)
            StuffHappened( e);
    }


    public void Start()
    {
        ThreadStart start = new ThreadStart(Run);
        worker = new Thread(start);
        worker.Start();
    }

    private void Run()
    {
        int i = 0;
        while (!_quit)
        {
            Thread.Sleep(1000);
            i++;
            OnStuffHappened(new MessageEventArgs(false, "it worked!"));
            Console.WriteLine(string.Format("Slept {0} seconds.",i));
        }
        Console.WriteLine("Thread exiting");
    }
}


public class MessageEventArgs : EventArgs
{
    public MessageEventArgs(bool Error, string message)
    {
        IsError = Error;
        Message = message;
    }

    public bool IsError { get; set; }
    public string Message { get; set; }
}

}

3 个答案:

答案 0 :(得分:1)

您是否必须使用此自定义线程系统,或者您是否可以使用BackgroundWorkersBackgroundWorkers有一个事件ProgressChanged在创建BackgroundWorker的线程上触发。

或者,如果您将处理程序附加到UI线程中的后台事件,则仍然可以在后台线程上完成工作。

thread.StuffHappenedDel += new EventHandler<MessageEventArgs>(StuffHappenedDel);

因此,您需要将数据编组到UI线程。一种方法是使用BeingInvoke

private void StuffHappenedDel(object sender, MessageEventArgs e)
{
    this.myControl.BeginInvoke( new Action(
     () => 
     {
           //UI thread work (likely anything that affects UI. Heavy      
          //processing can continue on the bg thread outside this code block
     }));
}

此外,您可以使用if (myControl.InvokeRequired)检查在更改特定控件时是否需要编组数据。

  if (this.InvokeRequired)
  {
       this.Invoke((Action)(() =>
       {
           //UI thread stuff
       }
       ));
  }

编辑以澄清

您创建的线程对象需要将事件处理程序附加到StuffHappenedDel事件。要做到这一点,你可以使用类似这样的东西

thread.StuffHappenedDel += new EventHandler<MessageEventArgs>(StuffHappenedDel);
在致电thread.Start()之前

。现在,这个处理程序被称为

private void StuffHappenedDel(Object seder, MessageEventArgs e)
{
    j++;
}
每当你的事件被解雇时

如果您想对任何UI元素进行更改,则需要使用上述Invoke方法。

答案 1 :(得分:1)

您需要将Form1注册为该事件的侦听器。首先,向Form1添加如下方法:

private void thread_SuffHappened(MessageEventArgs e)
{
    MessageBox.Show("Stuff happened!");
}

在Form1的构造函数中,像这样注册一个监听器:

public Form1()
{
    InitializeComponent();
    thread = new workerThread();
    thread.StuffHappened += new StuffHappenedDel(thread_StuffHappened);
    thread.Start();
}

答案 2 :(得分:0)

查看Background Worker Class。此外,您始终可以触发由GUI类处理的事件(尽管不在GUI线程上),然后调用Invoke