我正在编写一个触发事件的库。该库启动第二个线程,该线程连接到服务器并侦听消息(阻塞调用,第二个线程的原因)。
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;线程(我知道它与实例化我的类的线程相同)?
答案 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});
}
}
}