[英]Clever event accessors - to fire handlers on the thread they were registered?
Have just had an idea, I haven't seen it before, wondering if you guys thought it was a good idea, if it exists, any common pitfalls etc. - and also how to implement it. 刚刚有一个主意,我以前没看过,想知道你们是否认为这是个好主意,如果存在,任何常见的陷阱等-以及如何实施。
There are several times I've found myself subscribing to an event from the UI thread that will be called from a different thread - for example, notification of a service call completing. 有好几次我发现自己从UI线程中订阅了一个事件,该事件将从另一个线程中调用-例如,服务调用完成的通知。
'My' idea would be to store the current Dispatcher
in the add
block along with the handler delegate, then when the event is 'fired', perform some extra logic/checks to see if there was a dispatcher associated with the handler, and Invoke
on it if necessary. “我的想法”是将当前的
Dispatcher
与处理程序委托一起存储在add
块中,然后在事件被“触发”时,执行一些额外的逻辑/检查以查看是否有与该处理程序相关联的调度程序,并Invoke
如果需要的话。
Of course it would only work on threads with a Dispatcher
(or Forms equivalent - something with a message pump I guess). 当然,它仅适用于具有
Dispatcher
线程(或等效于Forms的线程-我猜它带有消息泵)。 I guess the usefulness and cleanliness depends on whether the event subscriber should have to worry about the thread the handler is called or not? 我猜是否有用和干净取决于事件订阅者是否应该担心处理程序被调用的线程?
Edit: Sounds like it's not such a bad thing then - additionally does anyone have any idea how to implement? 编辑:听起来那不是一件坏事-另外,有人不知道如何实现吗? Using
Delegate.Combine
how could you call each handler on a different Dispatcher
, for example? 例如,使用
Delegate.Combine
如何调用不同Dispatcher
上的每个处理程序? Would you instead store delegates in a composite object in a List
, and invoke them in turn in the On(Whatever)
method, or is there something nicer? 您是将委托存储在
List
的复合对象中,然后在On(Whatever)
方法中依次调用它们,还是有更好的方法?
...Looking at the BackgroundWorker
source in Reflector, there's nothing to Invoke: ...查看Reflector中的
BackgroundWorker
源,没有什么要调用的:
protected virtual void OnProgressChanged(ProgressChangedEventArgs e)
{
ProgressChangedEventHandler handler = (ProgressChangedEventHandler) base.Events[progressChangedKey];
if (handler != null)
{
handler(this, e);
}
}
Unless I'm missing something? 除非我想念什么?
So then BackgroundWorker
does it with an AsyncOperation
. 因此,然后
BackgroundWorker
使用AsyncOperation
。 How about a general solution, just for event handlers, in the event accessors? 仅针对事件处理程序的事件访问器中的常规解决方案怎么样?
BackgroundWorker
can get away with the way it works because a method is called from the client - in the more general case, the only time you'll have access to the handler's thread is in the event accessor? BackgroundWorker
可以摆脱它的工作方式,因为从客户端调用了一个方法-在更一般的情况下,您唯一可以访问处理程序线程的时间是在事件访问器中? :) :)
As far as I know, that's exactly what the BackgroundWorker
is doing in its RunWorkerCompleted
and ProgressChanged
events. 据我所知,这正是
BackgroundWorker
在其RunWorkerCompleted
和ProgressChanged
事件中所做的事情。 So it can't be that bad. 因此,不会那么糟。
I can't find a real proof, that the BackgroundWorker
is doing it, I just read it somewhere. 我找不到真正的证据证明
BackgroundWorker
正在这样做,只是在某处阅读过。 When you google for it , you will find more hints. 当您使用google搜索时 ,会发现更多提示。 If someone can provide a link, I would be happy.
如果有人可以提供链接,我会很高兴。
UPDATE: 更新:
Because it isn't so easy to find this behavior in the BackgroundWorker, I provide my analysis: 由于在BackgroundWorker中发现这种行为并不容易,因此我提供了以下分析:
The BackgroundWorker
is using an AsyncOperation
for raising the events. BackgroundWorker
使用AsyncOperation
引发事件。 Inside this class, the events are posted to a SynchronizationContext
. 在此类内部,事件被发布到
SynchronizationContext
。 Only then are the methods OnProgressChanged
and OnRunWorkerCompleted
executed. 然后,
OnRunWorkerCompleted
执行OnProgressChanged
和OnRunWorkerCompleted
方法。 This means, those methods are already executed on the right thread. 这意味着这些方法已经在正确的线程上执行。
In some more detail, the following happens, when RunWorkerAsync
is called: 更详细地说,在调用
RunWorkerAsync
时,会发生以下情况:
AsyncOperation
instance is created via AsyncOperationManager.CreateOperation
. AsyncOperationManager.CreateOperation
创建一个AsyncOperation
实例。 This saves the current SynchronizationContext
. SynchronizationContext
。 As we are still in the UI thread, this is the context of the UI thread. WorkerThreadStart
. WorkerThreadStart
。 This method is running in the background thread and executes OnDoWork
which in turn raises the DoWork
event. OnDoWork
,这将引发DoWork
事件。 This means, the DoWork
event is not raised in the UI thread. DoWork
事件。 OnDoWork
completed, the PostOperationCompleted
method of the AsyncOperation
instance is executed which in turn calls AsyncOperation.Post
which calls SynchronizationContext.Post
which in turn will call indirectly OnRunWorkerCompleted
on the UI thread. OnDoWork
完成后,将执行AsyncOperation
实例的PostOperationCompleted
方法,该方法依次调用AsyncOperation.Post
和SynchronizationContext.Post
,后者又将在UI线程上间接调用OnRunWorkerCompleted
。 ReportProgress
is called, a similar thing happens: AsyncOperation.Post
is called directly and will invoke the OnProgressChanged
method on the UI thread. ReportProgress
,会发生类似的事情:直接调用AsyncOperation.Post
,它将在UI线程上调用OnProgressChanged
方法。 AsyncOperation
and AsyncOperationManager
are public and can be used to implement a similar behavior in your classes. AsyncOperation
和AsyncOperationManager
是公共的,可用于在您的类中实现类似的行为。
我已经完成了与Castle IsInvokeRequired/Invoke
类似的操作,在此它拦截呼叫并对其进行IsInvokeRequired/Invoke
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.