从第二个线程引发事件到主线程,没有表单[重复]
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 从第二个线程调用函数