我迷失在这个问题中,我希望我的 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/