我正在编写一个WPF程序,其中我使用EventToCommand来处理第三方控件中的事件,并将它们连接到ICommands。我的视图模型方法都是异步的,我遇到的问题是事件没有等待处理程序完成。在WPF中说明问题有点长,但我在下面的小控制台应用程序中总结了这个问题。
我的主要问题是,是否有一个EventToCommand的实现允许我使用异步处理程序?是的,我做了谷歌,没有发现任何东西。mvvm文档这里没有提到异步。
我对完成任务的任何工作都持开放态度。注意,在下面的代码中,我使用了"ButtonClick“的名称,这可能会导致您问为什么我不只是绑定到命令.。这是一个错误的命名选择的例子对不起。在我的WPF应用程序中,我正在处理没有命令的事件。
class Program
{
public event EventHandler ButtonClickEvent;
static void Main(string[] args)
{
Console.WriteLine("Program");
var p = new Program();
}
public Program()
{
ButtonClickEvent += ButtonClickEventHandler;
Console.WriteLine("Start fire event");
ButtonClickEvent(this, new EventArgs()); // In WPF app this event is handled by EventToCommand, which executes an ICommand
Console.WriteLine("End fire event");
Console.Write("Press any key...");
Console.ReadKey();
// Output
// Start fire event
// Start GetStringAsync
// End fire event <-- not waiting
// End GetStringAsync
}
// In WPF app this method is wired up to a DelegateCommand
public async void ButtonClickEventHandler(object sender, EventArgs e)
{
await DownloadStuffAsync();
}
public async Task DownloadStuffAsync()
{
Console.WriteLine("Start GetStringAsync");
string page = await new HttpClient().GetStringAsync("http://www.ibm.com");
Console.WriteLine("End GetStringAsync");
}
}发布于 2015-10-13 06:00:06
EventHandlers不支持异步方法。您需要一些Task返回方法作为解决办法,并等待调用事件的Task。
您可以使用Stephen关于这个主题的文章中解释过的这里的延迟。还有其他解决方案,比如重写SynchronizationContext,但是使用上面所示的更好的解决方案。
发布于 2015-10-13 12:00:28
我遇到的问题是事件没有等待处理程序完成。 我的主要问题是,是否有一个EventToCommand的实现允许我使用异步处理程序?
好吧,从第三方控制的角度看问题。它引发了一个类似于这样的事件:
void ControlEvent(object sender, ControlEventArgs args);当委托返回时,它就完成了。事件处理程序签名返回void,所有参数都是从控件传递给事件处理程序的数据。没有“回传通讯”。委托没有办法告诉第三方控制:“我还没有完全完成;我只是返回释放线程,因为我是异步的;我有更多的代码要稍后执行,然后我将真正完成。”
因此,简而言之,您想要做的事情可能需要对第三方控件进行非琐碎的更改。有尝试强制异步代码同步完成的各种黑客攻击 (正如我在最近的一篇MSDN文章中所描述的),但是它们都没有很好的工作。正如Sriram所说,一个更好的解决方案是将第三方控件更改为使用延期;我在我的博客中描述了推迟执行的一项可能措施。然而,对于第三方控制而言,这将是一个重要的改变,他们可能不愿意这样做。
发布于 2015-10-13 06:16:12
我在WPF的评论中尝试了Sriram给出的链接解决方案,它确实有效。
我的ViewModel
public class ViewModel
{
public ICommand DoSomethingCommand { get; set; }
public ViewModel()
{
DoSomethingCommand = new RelayCommand(DoSomething);
}
private async void DoSomething()
{
await DownloadStuffAsync();
Debug.WriteLine("Button Call Completed");
}
public async Task DownloadStuffAsync()
{
Debug.WriteLine("Start GetStringAsync");
await Task.Run(() =>
{
Debug.WriteLine("Thread sleeping");
Thread.Sleep(5000);
}).ConfigureAwait(false);
string page = await new HttpClient().GetStringAsync("http://www.ibm.com").ConfigureAwait(false);
Debug.WriteLine("End GetStringAsync");
}
}我的观点
<StackPanel>
<Button Content="Do Something" Margin="0,2,2,2" Command="{Binding DoSomethingCommand}"/>
</StackPanel>和调试窗口上的输出。

https://stackoverflow.com/questions/33094950
复制相似问题