简体   繁体   English

WPF MVVM 异步事件调用

[英]WPF MVVM Async event invoke

I am lost in this one, i want my Viewmodel to use a event delegate so i can subscribe to it, open some dialog and wait for the dialog result.我迷失在这一点上,我希望我的 Viewmodel 使用事件委托,以便我可以订阅它,打开一些对话框并等待对话框结果。 Later the ViewModel should do whatever it wants with the dialog result.稍后 ViewModel 应该对对话框结果做任何它想做的事情。

Here is how i implemented it (resumed code):这是我实现它的方式(恢复代码):

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 is just a dialog where i search and return a TributaryDocument object. MyDocumentSearcherDialog只是一个对话框,我在其中搜索并返回一个TributaryDocument对象。

The problem to my understanding comes from this part (since i cant compile it):我理解的问题来自这部分(因为我无法编译它):

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

I cant use await without changing the method signature to async.我不能在不将方法签名更改为异步的情况下使用等待。 If i change it to async then i must return a Task<TributaryDocument> and change the event delegate:如果我将其更改为异步,那么我必须返回一个Task<TributaryDocument>并更改事件委托:

    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());
   }

If i do this i get the following exception:如果我这样做,我会得到以下异常:

Additional information: The calling thread must be STA, because many UI components require this.附加信息:调用线程必须是 STA,因为许多 UI 组件都需要它。

It seems like all you need to do is to remove the Task.Run (there is no need to Offload to another thread in this situation).似乎您需要做的就是删除Task.Run (在这种情况下无需卸载到另一个线程)。 The Task.Run will definitely give you a STA Thread Exception if you are doing UI work from within.如果您从内部进行UI工作, Task.Run肯定会给您一个STA 线程异常

However, in short the Async and Await Pattern will create a continuation with the current SynchronisationContext , so there is no need to worry about it.但是,简而言之, Async 和 Await 模式将创建一个与当前SynchronisationContext的延续,因此无需担心。

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

Note : Since this is an event, it's about the only place it's OK to use async void .注意:由于这是一个事件,因此它是唯一可以使用async void

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM