【发布时间】:2009-01-29 15:21:14
【问题描述】:
它有时想在等待事件发生时阻塞我的线程。
我通常这样做:
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;
}
但是,这似乎应该是我可以提取到公共类的东西(或者甚至可能是框架中已经存在的东西)。
我希望能够做这样的事情:
EventWaiter ew = new EventWaiter(button.Click);
ew.WaitOne();
EventWaiter ew2 = new EventWaiter(form.Closing);
ew2.WaitOne();
但是我真的找不到构造这样一个类的方法(我找不到将事件作为参数传递的有效方法)。有人可以帮忙吗?
要举例说明为什么这很有用,请考虑以下内容:
var status = ShowStatusForm();
status.ShowInsertUsbStick();
bool cancelled = WaitForUsbStickOrCancel();
if(!cancelled){
status.ShowWritingOnUsbStick();
WriteOnUsbStick();
status.AskUserToRemoveUsbStick();
WaitForUsbStickToBeRemoved();
status.ShowFinished();
}else{
status.ShowCancelled();
}
status.WaitUntilUserPressesDone();
这比使用在许多方法之间展开的逻辑编写的等效代码更简洁易读。但是要实现 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 */
我发现阅读起来要困难得多。诚然,流程并非总是如此线性,但当它是这样时,我喜欢第一种风格。
这与使用 ShowMessage() 和 Form.ShowDialog() 相当——它们也会阻塞,直到某些“事件”发生(尽管如果在 gui 线程上调用它们会运行消息循环)。
【问题讨论】:
-
我很好奇您究竟为什么要这样做...您能详细说明一下吗?
-
我还是不明白你为什么要阻塞线程而不是仅仅等待事件——这有什么作用?
-
你解决过这个问题吗?我也遇到了同样的问题。
-
@Carlo:对不起,不。我认为没有好的解决方案。
-
太糟糕了 =(,感谢您的快速回复!