c# - WPF MVVM 异步事件调用

标签 c# .net wpf mvvm async-await

我迷失在这个问题中,我希望我的 View 模型使用事件委托(delegate),这样我就可以订阅它,打开一些对话框并等待对话框结果。稍后,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<TributaryDocument>并更改事件委托(delegate):

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

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

Additional information: The calling thread must be STA, because many UI components require this.

最佳答案

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

但是,简而言之,异步和等待模式将使用当前SynchronizationContext创建延续,因此无需担心。

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

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

关于c# - WPF MVVM 异步事件调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55155514/

相关文章:

c# - 检查两个列表是否有相同的项目

c# - 非 WPF 应用程序中的隐式 WPF 样式

c# - DataGridTemplateColumn 不绑定(bind) ItemSource (WPF) 中的对象

.net - 为什么要使用List(T).Clear O(N)?

.net - System.Threading.Monitor.Enter() 如何工作?

c# - 如何将 'Pin this program to the taskbar' 添加到 Windows 7 的跳转列表中?

c# - 如何在 LINQ 中对单个连接中的多个字段进行左连接

c# - MS Sync/SQL Server Compact 代码在最新版本 SQL Compact 3.5 中失败

c# - 为什么人们不将依赖属性包装在通用类中?

c# - 使用 .Net HttpListener 的多线程