WPF MVVM Асинхронный вызов события - PullRequest
2 голосов
/ 14 марта 2019

Я заблудился в этом, я хочу, чтобы моя 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<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());
   }

Если я сделаю это, я получу следующее исключение:

Дополнительная информация: Вызывающий поток должен быть STA, потому что это требуется для многих компонентов пользовательского интерфейса.

1 Ответ

2 голосов
/ 14 марта 2019

Похоже, все, что вам нужно сделать, это удалить Task.Run (в этой ситуации нет необходимости выгружать в другой поток). Task.Run определенно даст вам STA Thread Exception , если вы выполняете UI работу изнутри.

Тем не менее, вкратце Асинхронный и ожидающий паттерн создаст продолжение с текущим SynchronisationContext , поэтому не нужно беспокоиться об этом

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

Примечание : Поскольку это событие, его единственное место, где его можно использовать async void

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...