它有时希望在等待事件发生时阻塞我的线程.
我通常会这样做:
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-thread上调用它们将运行消息循环).