的主要问题是,从一个线程引发事件可以调用代表只应在一定的线程上下文调用。做一些研究this问题我想,也许它可能通过某种同步上下文以及每个订阅的事件:
The main problem is, that raising an event from one thread can invoke delegates which should only invoked in a certain thread context. After doing some research on this problem i thought, maybe its possible to pass some kind of synchronization context along with each subscription to an event:
SomeClass.SmartSyncEvent += (myDelegate, someReferenceToAThread);
,然后引发该事件,并以某种方式做:
and then raise the event and it somehow does:
foreach(subscriber)
{
someReferenceToAThread.Invoke(myDelegate);
}
这是超级伪code,但也许有人已经做了这样的事情,或者知道任何.NET类可以建立这样一个格局。 谢谢!
This is super pseudo code, but maybe someone has already done things like this, or knows of any .NET classes which can set up such a pattern. thanks!
要做到这一点,最好的方法是通过 SomeClass的
通过同步上下文 ISynchronizeInvoke
。
The best way to do this is pass SomeClass
a synchronization context via ISynchronizeInvoke
.
public class SomeClass
{
public event EventHandler SmartSyncEvent;
public ISynchronizeInvoke SynchronizingObject { get; set; }
public void RaiseSmartSyncEvent()
{
if (SynchronizingObject != null)
{
SynchronizingObject.Invoke(
(Action)(()=>
{
SmartSyncEvent();
}), null);
}
else
{
SmartSyncEvent();
}
}
}
此模式类似于 System.Timers.Timer的
的实现方式。它存在的问题是,每一个订户将被编组到同一同步对象。它不会出现,这是你想要的,虽然事情。
This pattern is similar to the way System.Timers.Timer
is implemented. The problem with it is that every subscriber will be marshaled onto the same synchronizing object. It does not appear that this is what you want though.
幸运的是代表存储类的实例在其上的方法应该通过目标
属性来调用。我们可以通过提取它,我们调用委托之前,并将其作为利用此的在的同步对象当然假设它是一个 ISynchronizeInvoke
本身。我们实际上可以执行,通过使用自定义的添加和删除事件访问。
Fortunately delegates store the class instance upon which the method should be invoke via the Target
property. We can exploit this by extracting it before we invoke the delegate and using it as the synchronizing object assuming of course that it is a ISynchronizeInvoke
itself. We could actually enforce that by using custom add and remove event accessors.
public class SomeClass
{
private EventHandler _SmartSyncEvent;
public event EventHandler SmartSyncEvent
{
add
{
if (!(value.Target is ISynchronizeInvoke))
{
throw new ArgumentException();
}
_SmartSyncEvent = (EventHandler)Delegate.Combine(_SmartSyncEvent, value);
}
remove
{
_SmartSyncEvent = (EventHandler)Delegate.Remove(_SmartSyncEvent, value);
}
}
public void RaiseMyEvent()
{
foreach (EventHandler handler in _SmartSyncEvent.GetInvocationList())
{
var capture = handler;
var synchronizingObject = (ISynchronizeInvoke)handler.Target;
synchronizingObject.Invoke(
(Action)(() =>
{
capture(this, new EventArgs());
}), null);
}
}
}
这是一个很大的每个订户可以独立于其它编组更好。它的问题在于,处理程序必须驻留在 ISynchronizeInvoke
类实例的方法。此外, Delegate.Target
是静态方法无效。这就是为什么我执行与自定义添加约束
访问。
This is a lot better in that each subscriber can be marshaled independently of the others. The problem with it is that the handlers must be instance methods that reside in an ISynchronizeInvoke
class. Also, Delegate.Target
is null for static methods. This is why I enforce that constraint with the custom add
accessor.
你可以把它执行的同步处理,如果 Delegate.Target
为空或以其他方式不能被铸造成有用的同步对象。有对这个主题有很多变化。的
You could make it execute the handlers synchronously if Delegate.Target
were null or otherwise could not be casted into a useful synchronizing object. There are a lot of variations on this theme.
而不是 ISynchronizeInvoke
的在WPF中,你可以$ C $下 DispatcherObject的
。的
In WPF you could code for DispatcherObject
instead of ISynchronizeInvoke
.