WPF MVVM Асинхронный вызов события

2

Я заблудился в этом, я хочу, чтобы моя 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 без изменения сигнатуры метода на async. Если я изменю его на асинхронный, тогда я должен вернуть 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, потому что это требуется для многих компонентов пользовательского интерфейса.

  • 0
    Вы сказали нам, что хотите, и предоставили свой код, и это хорошо, но вы точно не объяснили, как текущий код не соответствует вашим потребностям. Мы не должны угадывать или отрабатывать вещи, которые вы уже знаете.
  • 0
    Вы должны решить эту проблему с помощью интерфейса службы, который имеет асинхронный метод SearchDocumentAsync. Одна реализация вызовет диалог
Показать ещё 1 комментарий
Теги:
wpf
async-await
mvvm

1 ответ

2
Лучший ответ

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

Тем не менее, короче говоря, Async и Await Pattern создадут продолжение с текущим SynchronisationContext, поэтому не нужно беспокоиться об этом.

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню