多线程c#winforms中的事件处理

时间:2014-02-07 13:39:10

标签: c# multithreading winforms c#-4.0 event-handling

我开发了多线程应用程序,用于在线程中完成事件处理。当UI线程中的事件引发时,会创建一个执行业务逻辑并终止的线程。但是,如果工作线程中的业务逻辑代码导致另一个事件; thread在主UI线程上调用控件并继续执行。同时,UI线程为新事件处理创建新线程。这两个线程都以并行方式执行。

我想要的是,如果线程导致新事件;等待新的事件completition并继续他们的任务。应按顺序处理事件。

我的任务实际上是大型框架的一部分。简言之,应用程序通过使用反射api将控制事件绑定到目标代码。

下面的UI线程处理代码捕获事件时。

 Thread workerThread = new Thread(() => executeCommandTargetAsync( ..some parameters.. ));
 workerThread.Start();

Worker线程通过使用Control的InvokeRequired标志和Invoke方法与UI Thread进行通信。 处理其他线程中的事件而不是UI线程的目的阻止因长事件操作而冻结UI,例如从数据库更改组合框的数据源。

2 个答案:

答案 0 :(得分:1)

尝试使用“AutoResetEvent”类:

 AutoResetEvent resetEvent = new AutoResetEvent(false);

 resetEvent.WaitOne();


 //pass the resetEvent object to thread 2, and when you want to continue processing the thread 1 you use the method resetEvent.Set();

答案 1 :(得分:1)

在主UI线程中运行以下内容将是灾难性的,因为UI将被冻结且无响应。

AutoResetEvent resetEvent = new AutoResetEvent(false);
resetEvent.WaitOne();

相反,你可以使用信号和计时器。 在你的winforms应用程序中创建一个事件args队列或其他合适的包装器来捕获引发事件的本质,并在线程同步锁中包装队列和出队

在您创建的单独线程中,而不是引发事件将数据或信号排入队列。

在你的winodws表单中,应用程序有一个计时器,可以轮询队列中的任何新事件,并相应地处理这些事件。

如果您使用以下示例代码,那么: 1)当其中一个控件引发事件时,只需调用EnqueueEvent而不是启动新线程 2)在你的新线程中你要做的只是用一个新信号调用EnqueueEvent而不是引发一个事件。 当然,用适合您场景的东西替换MyEventSignal类,并将计时器代码放在实际的计时器处理程序中。

public class MyEventSignal
{
    public MyEventSignal()
    {
    }
    public MyEventSignal(object _Sender, EventArgs _Args)
    {
        Sender = _Sender;
        Args = _Args;
    }
    object Sender { get; set; }

    EventArgs Args { get; set; }
}

private static object syncRoot = new object();
private static Queue<MyEventSignal> eventSignalQueue = new Queue<MyEventSignal>();
public static void EnqueueEvent(MyEventSignal NewEventSignal)
{
    lock (syncRoot)
    {
        eventSignalQueue.Enqueue(NewEventSignal);
    }
}

private static MyEventSignal DequeueEvent()
{
    MyEventSignal result;
    result = null;
    lock (syncRoot)
    {
        if (eventSignalQueue.Count > 0)
        {
            result = eventSignalQueue.Dequeue();
        }
    }
    return result;
}

private void TimerUI_Tick(object sender, EventArgs e)
{
    MyEventSignal newSignal;
    newSignal = DequeueEvent();
    while (newSignal != null)
    {
        // start new thread to do stuff based on event signal
        newSignal = DequeueEvent();
    }
}


private void DoStuffOnParalleThread()
{
    System.Threading.ThreadStart MyThreadStart;
    System.Threading.Thread MyThread;
    MyThreadStart = new System.Threading.ThreadStart(WorkerThreadRoutine);
    MyThread = new System.Threading.Thread(MyThreadStart);
    MyThread.Start()
}

private void WorkerThreadRoutine()
{
    // Do stuff

    //Instead of raising an event do this of course specify your event args
    // or change the MyEventSignal class to suit
    Form1.EnqueueEvent(new WinApp.Form1.MyEventSignal(this, EventArgs.Empty));
}