如何“等待"引发 EventHandler 事件 [英] How to 'await' raising an EventHandler event

查看:30
本文介绍了如何“等待"引发 EventHandler 事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有时,事件模式用于在 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 重构我的应用程序时,我正在制作尽可能多的代码以使用 asyncawait.但是以下不起作用(好吧,我真的没想到它会起作用)

 await SearchRequest(this, EventArgs.Empty);

框架确实这样做是为了调用事件处理程序 比如这个,但我不知道它是怎么做到的?

private async void button1_Click(object sender, RoutedEventArgs e){textBlock1.Text = "点击开始";等待 DoWork();textBlock2.Text = "点击完成";}

我发现的关于异步引发事件的任何内容 但我在框架中找不到支持这一点的东西.

我怎样才能等待一个事件的调用,但仍然停留在 UI 线程上.

解决方案

正如您所发现的,事件与 asyncawait 并不完美结合.>

用户界面处理 async 事件的方式与您尝试做的不同.UI 为其async<提供SynchronizationContext/code> 事件,使它们能够在 UI 线程上恢复.它不会等待"

最佳解决方案 (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 SynchronizationContexts 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆