它有时希望在等待事件发生时阻塞我的线程.
我通常会这样做:
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private void OnEvent(object sender, EventArgs e){
_autoResetEvent.Set();
}
// ...
button.Click += OnEvent;
try{
_autoResetEvent.WaitOne();
}
finally{
button.Click -= OnEvent;
}
Run Code Online (Sandbox Code Playgroud)
但是,似乎这应该是我可以提取到一个公共类(或者甚至可能已经存在于框架中的东西)的东西.
我希望能够做到这样的事情:
EventWaiter ew = new EventWaiter(button.Click);
ew.WaitOne();
EventWaiter ew2 = new EventWaiter(form.Closing);
ew2.WaitOne();
Run Code Online (Sandbox Code Playgroud)
但我真的找不到构建这样一个类的方法(我找不到一个好的方法来将事件作为参数传递).有人可以帮忙吗?
举一个为什么这个有用的例子,考虑这样的事情:
var status = ShowStatusForm();
status.ShowInsertUsbStick();
bool cancelled = WaitForUsbStickOrCancel();
if(!cancelled){
status.ShowWritingOnUsbStick();
WriteOnUsbStick();
status.AskUserToRemoveUsbStick();
WaitForUsbStickToBeRemoved();
status.ShowFinished();
}else{
status.ShowCancelled();
}
status.WaitUntilUserPressesDone();
Run Code Online (Sandbox Code Playgroud)
这比使用在许多方法之间展开的逻辑编写的等效代码更简洁和可读.但是要实现WaitForUsbStickOrCancel(),WaitForUsbStickToBeRemoved和WaitUntilUserPressesDone()(假设我们在插入或删除usb棒时得到一个事件)我需要每次都重新实现"EventWaiter".当然,你必须要小心,永远不要在GUI线程上运行它,但有时这对于更简单的代码来说是值得的权衡.
替代方案看起来像这样:
var status = ShowStatusForm();
status.ShowInsertUsbStick();
usbHandler.Inserted += OnInserted;
status.Cancel += OnCancel;
//...
void OnInserted(/*..*/){
usbHandler.Inserted -= OnInserted;
status.ShowWritingOnUsbStick();
MethodInvoker mi = () => WriteOnUsbStick();
mi.BeginInvoke(WritingDone, null);
}
void WritingDone(/*..*/){
/* EndInvoke */
status.AskUserToRemoveUsbStick();
usbHandler.Removed += OnRemoved;
}
void OnRemoved(/*..*/){
usbHandler.Removed -= OnRemoved;
status.ShowFinished();
status.Done += OnDone;
}
/* etc */
Run Code Online (Sandbox Code Playgroud)
我发现阅读起来更难.不可否认,流量将永远不会那么线性,但是当它如此时,我喜欢第一种风格.
它与使用ShowMessage()和Form.ShowDialog()相当 - 它们也会阻塞直到某些"事件"发生(尽管如果在gui-thread上调用它们将运行消息循环).
我修改了 Dead.Rabit 的 EventWaiter 类来处理EventHandler<T>
. 因此,您可以使用 等待所有事件类型EventHandler<T>
,这意味着您的委托类似于delegate void SomeDelegate(object sender, T EventsArgs)
.
public class EventWaiter<T>
{
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private EventInfo _event = null;
private object _eventContainer = null;
public EventWaiter(object eventContainer, string eventName)
{
_eventContainer = eventContainer;
_event = eventContainer.GetType().GetEvent(eventName);
}
public void WaitForEvent(TimeSpan timeout)
{
EventHandler<T> eventHandler = new EventHandler<T>((sender, args) => { _autoResetEvent.Set(); });
_event.AddEventHandler(_eventContainer, eventHandler);
_autoResetEvent.WaitOne(timeout);
_event.RemoveEventHandler(_eventContainer, eventHandler);
}
}
Run Code Online (Sandbox Code Playgroud)
例如,当我注册到 Windows 推送通知服务时,我使用它来等待从 HttpNotificationChannel 获取 Url。
HttpNotificationChannel pushChannel = new HttpNotificationChannel(channelName);
//ChannelUriUpdated is event
EventWaiter<NotificationChannelUriEventArgs> ew = new EventWaiter<NotificationChannelUriEventArgs>(pushChannel, "ChannelUriUpdated");
pushChannel.Open();
ew.WaitForEvent(TimeSpan.FromSeconds(30));
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
39933 次 |
最近记录: |