将事件从第二个线程引发到主线程,没有表单

时间:2017-01-03 13:25:26

标签: c# multithreading events invoke

我正在编写一个触发事件的库。该库启动第二个线程,该线程连接到服务器并侦听消息(阻塞调用,第二个线程的原因)。

public virtual event LogEventHandler EntryReceived;

protected virtual void ReceiveEntry(ILogEntry entry)
{
    if (EntryReceived != null)
        EntryReceived(this, new LogEventArgs() { Entry = entry });
}

当从服务器收到消息时,它正在触发一个事件:

ReceiveEntry(entry);

我希望end developper不必考虑事件处理程序中的InvokeRequired / Invoke代码段。我怎样才能确保在父母身上发起我的活动?#34;线程(我知道它与实例化我的类的线程相同)?

2 个答案:

答案 0 :(得分:0)

为此目的,有一些winforms元素称为SynchronizingObject属性。此属性的类型为ISynchronizeInvoke,它具有在UI线程中执行调用所需的方法。

在您的代码中,您检查此属性是否为null,如果已设置,则使用它:

var sync = this.SynchronizingObject;

if (sync != null && sync.InvokeRequired)
    sync.BeginInvoke(new Action(()=> ReceiveEntry(entry), null);
else                        
   ReceiveEntry(entry); 

库的用户只需将Control或Form放入该属性:

private MyLibraryClass _MyLibraryClass;

public Form1()
{
    InitializeComponent();

    _MyLibraryClass = new MyLibraryClass();
    _MyLibraryClass.SynchronizingObject = this;
    _MyLibraryClass.EntryReceived += OnEntryReceived;
}

private void OnEntryReceived(object sender, LogEventArgs e)
{
    myTextBox.Text += e.Entry.Message;
}

答案 1 :(得分:0)

如果在对象构造期间捕获SynchronizationContext,您将能够在该上下文中发送事件(如果有),如果没有上下文,那么您的类是在不关心哪个线程上构建的线程将用于引发事件。这比ISynchronizeInvoke更好,因为SynchronizationContext可以与WinForms,ASP.NET和WPF一起使用,其中ISynchronizeInvoke仅适用于WinForms。

C#6版

public class Example
{
    private SynchronizationContext _context;

    public Example()
    {
        var existingContext = SynchronizationContext.Current;
        _context = existingContext?.CreateCopy() ?? new SynchronizationContext();
    }


    public virtual event LogEventHandler EntryReceived;

    protected virtual void ReceiveEntry(ILogEntry entry)
    {
        _context.Send(ContextCallback, entry);
    }

    private void ContextCallback(object entry)
    {
        EntryReceived?.Invoke(this, new LogEventArgs() { Entry = (ILogEntry)entry });
    }
}

C#5及更低版本

public class Example
{
    private SynchronizationContext _context;

    public Example()
    {
        var existingContext = SynchronizationContext.Current;
        _context = existingContext != null ? existingContext.CreateCopy() : new SynchronizationContext();
    }


    public virtual event LogEventHandler EntryReceived;

    protected virtual void ReceiveEntry(ILogEntry entry)
    {
        _context.Send(ContextCallback, entry);
    }

    private void ContextCallback(object entry)
    {
        var temp = EntryReceived;
        if (temp != null)
        {
            temp(this, new LogEventArgs() {Entry = (ILogEntry)entry});
        }
    }
}
相关问题