EventToCommand异步?

时间:2015-10-13 05:42:37

标签: c# wpf async-await mvvm-light

我正在编写一个WPF程序,我使用EventToCommand处理第三方控件中的事件并将它们连接到ICommands。我的视图模型方法都是异步的,我遇到的问题是事件不等待处理程序完成。问题在WPF中有点长,但我在下面的小控制台应用程序中总结了它。

我的一般问题是EventToCommand的实现是否允许我使用异步处理程序?是的,我确实谷歌没有发现任何东西。 mvvm-light文档here没有提到异步。

我愿意接受任何完成工作的工作。请注意下面的代码我使用名称" 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");
    }
}

4 个答案:

答案 0 :(得分:2)

EventHandlers不支持异步方法。您需要一些Task返回方法作为解决方法,并等待调用该事件的Task

您可以按照Stephen Cleary关于此主题的文章中的here解释使用Deferral。还有其他解决方案,例如覆盖SynchronizationContext,但使用上面文章中显示的内容会更好。

答案 1 :(得分:1)

  

我遇到的问题是事件不等待处理程序完成。

     

我的一般问题是EventToCommand的实现是否允许我使用异步处理程序?

好吧,从第三方控件的角度来看问题。它提出的事件看起来像这样:

void ControlEvent(object sender, ControlEventArgs args);

当该代表返回时,已完成。事件处理程序签名返回void,所有参数都是从控件传递到事件处理程序的数据。没有&#34;返回通信&#34;。代表没有办法告诉第三方控件&#34;我还没有完全完成;我只是回来释放线程,因为我是异步的;我有更多代码可以在以后执行,然后我

因此,简而言之,您想要做的事情可能需要对第三方控件进行非平凡的更改。有various hacks to try to force the asynchronous code to complete synchronously(正如我在最近的MSDN文章中所描述的那样),但它们都不能很好地工作。斯里兰姆所说的更好的解决方案是改变第三方控制以使用Deferrals;我在博客上描述了one possible implementation of Deferrals。但是,对于第三方控件来说,这将是一个非平凡的变化,他们可能不愿意这样做。

答案 2 :(得分:0)

我尝试使用Sriram在我在WPF的评论中提供的链接上的解决方案,它确实有效。

我的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>

和调试窗口上的输出

enter image description here

答案 3 :(得分:0)

Sam事件只不过是一个触发器,可以通知按钮单击或鼠标移动等事情。如果你想开始做那件事。但在那之后处理你的异步需求。能否请您详细说明您的需求。这样我可以提供更多帮助吗?

由于 Ankit