【问题标题】:WPF MVVM Async event invokeWPF MVVM 异步事件调用
【发布时间】:2019-08-04 22:25:29
【问题描述】:

我迷路了,我希望我的 Viewmodel 使用事件委托,以便我可以订阅它,打开一些对话框并等待对话框结果。稍后,ViewModel 应该对对话结果做任何事情。

这是我实现它的方式(恢复代码):

public class MyViewModel()
{
   public delegate TributaryDocument SearchDocumentEventHandler();
   public event SearchDocumentEventHandler SearchDocument;

   //Command for the search button
   public CommandRelay SearchDocumentCommand { get; set; }

   //Document that i found in the dialog.
   public TributaryDocument Document { get; set; }

   public MyViewModel()
   {
      SearchDocumentCommand = new CommandRelay(DoSearchDocument);
   }

   //The command execution
   public void DoSearchDocument()
   {
       //Event used here !
       Document = SearchDocument?.Invoke();
   }
}

public class MyUIControl : UserControl
{
    public MainWindow MainWindow { get; }

    public MyUIControl()
    {
       MainWindow = Application.Current.Windows[0] as MainWindow;
       DataContextChanged += MyUIControl_DataContextChanged;
    }

    private void MyUIControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var modelView = (MyViewModel)DataContext;
        modelView.SearchDocument += MyUIControl_SearchDocument;
    }

    private TributaryDocument MyUIControl_SearchDocument()
    {
       //Dont know what to do here... i am lost on this part.
       return await MainWindow.ShowDialog(new MyDocumentSearcherDialog());
    }
}

//The signature for MainWindow.ShowDialog
public async Task<object> ShowDialog(object dialog)
{
   return await DialogHost.Show(dialog, "MainDialog");
}

MyDocumentSearcherDialog 只是一个对话框,我在其中搜索并返回 TributaryDocument 对象。

我理解的问题来自这部分(因为我无法编译它):

private TributaryDocument MyUIControl_SearchDocument()
{
   return await MainWindow.ShowDialog(new MyDocumentSearcherDialog());
}

如果不将方法签名更改为异步,我将无法使用 await。如果我将其更改为异步,那么我必须返回 Task&lt;TributaryDocument&gt; 并更改事件委托:

    public delegate Task<TributaryDocument> SearchDocumentEventHandler();

    //On MyUIControl
    private Task<TributaryDocument> MyUIControl_SearchDocument()
    {
       return await MainWindow.ShowDialog(new MyDocumentSearcherDialog());
    }

   //On MyViewModel
   public async void DoSearchDocument()
   {
       //Event used here !
       Document = await Task.Run(async () => await SearchDocument?.Invoke());
   }

如果我这样做,我会得到以下异常:

附加信息:调用线程必须是STA,因为很多 UI 组件需要这个。

【问题讨论】:

  • 您已经告诉我们您想要做什么,并且您已经提供了您的代码,这很好,但是您没有准确解释当前代码如何不能满足您的需求。我们不必猜测或解决您已经知道的事情。
  • 您应该使用具有异步方法 SearchDocumentAsync 的服务接口来解决此问题。一种实现将调用对话框
  • 那里,我试过了。

标签: c# .net wpf mvvm async-await


【解决方案1】:

似乎您需要做的就是删除Task.Run(在这种情况下,不需要卸载到另一个线程)。如果您从内部进行 UI 工作,Task.Run 肯定会给您一个 STA 线程异常

不过,简而言之,Async 和 Await 模式 将创建与当前 SynchronisationContext 的延续,因此无需担心。

public async void DoSearchDocument()
{ 
   await SearchDocument?.Invoke();
}

注意:由于这是一个事件,它是唯一可以使用async void的地方。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-20
    • 2019-07-31
    • 2011-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    相关资源
    最近更新 更多