从第二个线程引发事件到主线程,没有表单[重复]

Posted

技术标签:

【中文标题】从第二个线程引发事件到主线程,没有表单[重复]【英文标题】:Raise event from second thread to main thread, without forms [duplicate] 【发布时间】:2017-05-17 14:35:56 【问题描述】:

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

public virtual event LogEventHandler EntryReceived;

protected virtual void ReceiveEntry(ILogEntry entry)

    if (EntryReceived != null)
        EntryReceived(this, new LogEventArgs()  Entry = entry );

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

ReceiveEntry(entry);

我希望最终开发人员不必在他的事件处理程序中考虑 InvokeRequired/Invoke sn-p。我如何确保在“父”线程(我知道它与实例化我的类的线程相同)上触发我的事件?

【问题讨论】:

【参考方案1】:

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

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

var sync = this.SynchronizingObject;

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

库的用户只需将控件或表单放入该属性:

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;

【讨论】:

【参考方案2】:

如果在对象构造期间您捕获了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);
        
    

【讨论】:

以上是关于从第二个线程引发事件到主线程,没有表单[重复]的主要内容,如果未能解决你的问题,请参考以下文章

多线程 dll 和 lock whan 从第二个线程调用函数

一个线程中对 MOC 属性的更改未传播到主线程

使用 PyQT 从第二个表单中捕获按钮方法

UI线程上的.NET引发事件[重复]

c++ 当在一个线程中写入并在第二个线程中读取同一个对象时会发生啥? (它安全吗?)[重复]

事件循环(event loop)