如何“等待"引发 EventHandler 事件 [英] How to 'await' raising an EventHandler event
问题描述
有时,事件模式用于在 MVVM 应用程序中引发事件,由子视图模型或子视图模型以这种松散耦合的方式向其父视图模型发送消息.
父视图模型
searchWidgetViewModel.SearchRequest += (s,e) =>{搜索订单(searchWidgitViewModel.SearchCriteria);};
SearchWidget ViewModel
公共事件EventHandler SearchRequest;SearchCommand = new RelayCommand(() => {IsSearching = true;如果(搜索请求!= null){SearchRequest(this, EventArgs.Empty);}IsSearching = false;});
<小时>
在为 .NET4.5 重构我的应用程序时,我正在制作尽可能多的代码以使用 async
和 await
.但是以下不起作用(好吧,我真的没想到它会起作用)
await SearchRequest(this, EventArgs.Empty);
框架确实这样做是为了调用事件处理程序 比如这个,但我不知道它是怎么做到的?
private async void button1_Click(object sender, RoutedEventArgs e){textBlock1.Text = "点击开始";等待 DoWork();textBlock2.Text = "点击完成";}
我发现的关于异步引发事件的任何内容是 古 但我在框架中找不到支持这一点的东西.
我怎样才能等待
一个事件的调用,但仍然停留在 UI 线程上.
正如您所发现的,事件与 async
和 await
并不完美结合.>
用户界面处理 async
事件的方式与您尝试做的不同.UI 为其async<提供
,使它们能够在 UI 线程上恢复.它不会等待"SynchronizationContext
/code> 事件
最佳解决方案 (IMO)
我认为最好的选择是使用 AsyncCountdownEvent
以了解所有处理程序何时完成.
次要解决方案 #1
async void
方法会在开始和结束时通知它们的 SynchronizationContext
(通过增加/减少异步操作的计数).所有 UI SynchronizationContext
都忽略这些通知,但您可以构建一个包装器来跟踪它并在计数为零时返回.
这是一个示例,使用我的 AsyncEx 库中的 AsyncContext
:
SearchCommand = new RelayCommand(() => {IsSearching = true;如果(搜索请求!= null){AsyncContext.Run(() => SearchRequest(this, EventArgs.Empty));}IsSearching = false;});
然而,在这个例子中,UI 线程在 Run
中不泵送消息.
次要解决方案 #2
您还可以基于嵌套的 Dispatcher
框架创建自己的 SynchronizationContext
,该框架在异步操作计数达到零时自行弹出.但是,您随后会引入重入问题;DoEvents
被故意排除在 WPF 之外.
Sometimes the event pattern is used to raise events in MVVM applications by or a child viewmodel to send a message to its parent viewmodel in a loosely coupled way like this.
Parent ViewModel
searchWidgetViewModel.SearchRequest += (s,e) =>
{
SearchOrders(searchWidgitViewModel.SearchCriteria);
};
SearchWidget ViewModel
public event EventHandler SearchRequest;
SearchCommand = new RelayCommand(() => {
IsSearching = true;
if (SearchRequest != null)
{
SearchRequest(this, EventArgs.Empty);
}
IsSearching = false;
});
In refactoring my application for .NET4.5 I am making as much as code possible to use async
and await
. However the following doesn't work (well I really wasn't expecting it to)
await SearchRequest(this, EventArgs.Empty);
The framework definitely does this to call event handlers such as this, but I'm not sure how it does it?
private async void button1_Click(object sender, RoutedEventArgs e)
{
textBlock1.Text = "Click Started";
await DoWork();
textBlock2.Text = "Click Finished";
}
Anything I've found on the subject of raising events asynchrously is ancient but I can't find something in the framework to support this.
How can I await
the calling of an event but remain on the UI thread.
Events don't mesh perfectly with async
and await
, as you've discovered.
The way UIs handle async
events is different than what you're trying to do. The UI provides a SynchronizationContext
to its async
events, enabling them to resume on the UI thread. It does not ever "await" them.
Best Solution (IMO)
I think the best option is to build your own async
-friendly pub/sub system, using AsyncCountdownEvent
to know when all handlers have completed.
Lesser Solution #1
async void
methods do notify their SynchronizationContext
when they start and finish (by incrementing/decrementing the count of asynchronous operations). All UI SynchronizationContext
s ignore these notifications, but you could build a wrapper that tracks it and returns when the count is zero.
Here's an example, using AsyncContext
from my AsyncEx library:
SearchCommand = new RelayCommand(() => {
IsSearching = true;
if (SearchRequest != null)
{
AsyncContext.Run(() => SearchRequest(this, EventArgs.Empty));
}
IsSearching = false;
});
However, in this example the UI thread is not pumping messages while it's in Run
.
Lesser Solution #2
You could also make your own SynchronizationContext
based on a nested Dispatcher
frame that pops itself when the count of asynchronous operations reaches zero. However, you then introduce re-entrancy problems; DoEvents
was left out of WPF on purpose.
这篇关于如何“等待"引发 EventHandler 事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!