Я заблудился в этом, я хочу, чтобы моя 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, потому что это требуется для многих компонентов пользовательского интерфейса.
Похоже, что все, что вам нужно сделать, это удалить Task.Run
(нет необходимости выгружать в другой поток в этой ситуации). Task.Run
определенно даст вам исключение Task.Run
STA, если вы выполняете работу интерфейса изнутри.
Тем не менее, короче говоря, Async и Await Pattern создадут продолжение с текущим SynchronisationContext, поэтому не нужно беспокоиться об этом.
public async void DoSearchDocument()
{
await SearchDocument?.Invoke();
}
Примечание. Поскольку это событие, его единственное место, где можно использовать async void
ОК.