2014-10-07 50 views
0

我使用了一个独立的类,根据机器的类型实例化不同的条形码对象,一旦读取条形码就会引发事件。所以为了将它传递给表单,我还提出了一个UNIQUE事件'myEvent',表示我所有的表单都在侦听,但是在表单内部我必须使用this.Invoke((Action)mymethod(argument));以便能够在用户界面更新组件,只要myEvent的处理程序在另一个不同于表单的线程上执行。避免在c#精简框架中的事件处理函数上使用this.Invoke(..)

所以我有这样的:

我的班级 - > barcode.readed(..)被触发,然后从它的处理程序中,我提出myEvent,即俘获了我的表上,并从处理程序myEvent上我的表单,我执行this.Invoke ...我知道这是一个有点标准的程序,但我想摆脱该调用,而是直接调用myMethod(参数);功能。

我认为这与使我的类线程安全有关,但我不知道如何在我的情况下实现。

事实上,如果我使用原始的制造商barcode.readed()事件从窗体内部它不需要调用调用,只要这是线程安全的,但我不知道如何模仿,而且我真的需要在不同的项目中包装所有不同的条形码处理程序,因为我的表单只使用一个返回所需条形码的'myEvent',因此不会重复代码。

由于提前,

罗杰Tranchez

回答

0

听起来你正在使用的工作线程读取条形码,以保持UI响应。条形码对象只是运行在任何创建它的线程上。

您可以集中事件处理(以避免重复代码)和阅读工作线程条码如下:

  • 包裹的自定义对象/库MyBarcodeReader暴露MyEvent内条码对象。
  • 在MyBarcodeReader的构造函数中,将当前SynchronizationContext捕获到类字段syncContext。如果您的表单构造MyBarcodeReader,这将是您的UI的SynchronizationContext。
  • 当您激活MyBarcodeReader(例如MyBarcodeReader.Execute)时,请在工作线程上创建条形码对象。
  • 当您需要提升MyEvent时,请调用syncContext.Send(这将在工作线程上),传递一个旨在引发MyEvent的委托。 syncContext.Send将同步到UI线程(如Control.Invoke)。下面的代码说明了这一点。

public class MyBarcodeReader 
{ 
    private readonly SynchronizationContext syncContext; 

    // Handler for barcode object's Readed event. 
    private void Barcode.Readed(Object sender, Event e) 
    { 
     // Block the worker thread to synchronize with the thread associated 
     // with SynchronizationContext. 
     syncContext.Send(SyncMyEvent, (Object)e); 
    } 

    // Raises MyEvent on the thread associated with SynchronizationContext, 
    // usually a UI thread. 
    private void SyncMyEvent(Object o) 
    { 
     if (MyEvent != null) 
     { 
      MyEvent((Event)o); 
     } 
    } 

    // Constructor. 
    public MyBarcodeReader() 
    { 
     syncContext = SynchronizationContext.Current; 
    } 
} 

这里的方法将阻止工作线程(同Control.Invoke),但不阻止用户界面线程。如果您有一个或多个订阅MyEvent的表单,则不需要使用Control.Invoke;他们甚至不需要知道工作者线程。

SynchronizationContext上有一些优秀的在线参考,请参阅CodeProjectMSDN magazine

+0

谢谢!我没有明确地使用工作线程,我只是实例化包含引发事件的本地对象的类,然后从该类中提出我自己的事件,并将其捕获到表单中。 我与Compact Framework的3.5工作,不具有的SynchronizationContext功能。 我试图用这个[执行](http://www.planetgeek.ch/2009/02/03/part-i-mimic-synchronizationcontext-behaviour-on-net-cf/) 但它没由于该示例没有实现.Current成员,因此不起作用。 我想我需要另一种方法... – Roger 2014-10-08 10:36:06

+0

如果实施例没有实现.Current成员为什么不使用类的实例,如'syncContext = SynchronizationContext'?您可以查看的另一个选项是http://nitoasync.codeplex.com/。 – groverboy 2014-10-08 23:36:12

0

我找到了解决方案here:基本上,它将表单控件传递给类构造函数,然后在该类内部使用form.Invoke从窗体UI线程触发事件。

类:

using System; 
using System.Windows.Forms; 
using System.Threading; 

namespace ThreadTest 
{ 
    public class WorkerClass 
    { 
     private Thread thr; 

     // UI control for update 
     public Control UIControl { get; set; } 

     public delegate void StatusUpdate(DateTime dateTime, string message); 
     public event StatusUpdate OnStatusUpdate; 

     // Starts thread 
     public void Start() 
     { 
      thr = new Thread(new ThreadStart(MainWorker)); 
      thr.Start(); 
     } 

     // Main thread worker 
     public void MainWorker() 
     { 
      int i = 0; 

      while (true) 
      { 
       string message = string.Format("Value of i={0}", i++); 
       FireStatusUpdate(DateTime.Now, message); 

       Thread.Sleep(1000); 
      } 
     } 

     // Fire thread safe event 
     private void FireStatusUpdate(DateTime dateTime, string message) 
     { 
      // UIControl is set and OnStatusUpdate has subscriber 
      if (UIControl != null && OnStatusUpdate != null) 
      { 
       if (UIControl.InvokeRequired) 
       { 
        UIControl.Invoke(new StatusUpdate(FireStatusUpdate), 
              new object[] { dateTime, message }); 
        return; 
       } 

       OnStatusUpdate(dateTime, message); 
      } 
     } 
    } 
} 

FORM:

using System; 
using System.Drawing; 
using System.Windows.Forms; 

namespace ThreadTest 
{ 
    public partial class Form1 : Form 
    {   
     public Form1() 
     { 
      InitializeComponent(); 

      WorkerClass worker = new WorkerClass(); 
      // add event handler 
      worker.OnStatusUpdate += new WorkerClass.StatusUpdate(worker_OnStatusUpdate); 
      // add UI control to invoke 
      worker.UIControl = this; 
      worker.Start(); 
     } 

     void worker_OnStatusUpdate(DateTime dateTime, string message) 
     { 
      label1.Text = dateTime.ToLongTimeString(); 
      label1.Text += " " + message; 
     } 
} 

就我而言,我已经改变了事件的类型,从StatusUpdate到

EventHandler<MyEventArgs> 

,是MyEventArgs这个类:

public class MyEventArgs : EventArgs 
{ 
    public string MyString { get; set; } 
} 

谢谢!

2

如果你继承你的控制类(基本上是创建一个新的自定义控制),你可以处理,而无需使用调用作为对照(条形码阅读器类)在UI线程上的事件是在UI线程的一部分。

+0

太棒了!它的工作,谢谢:我创建了一个新的自定义控件。然后,我不得不将设计器中的保护覆盖void Dispose(bool disposing)剪切到我的自定义控件类中,因为如果我没有这样做,我不能在我的类中实现破坏我的条形码阅读器。最后,自定义控件的创建会自动创建OnPaint函数:据我所知,我可以保持原样,因为我的控件没有任何接口。这是对的吗 ? – Roger 2014-10-10 15:58:30

+0

对,如果你的'控件'没有绘制任何东西,你不需要绘制代码。 – josef 2014-10-11 06:11:47