在长时间执行以Task.Run()
启动的异步方法期间,我可能需要找回用户以进行其他输入或确认,例如必须在UI线程上执行的消息框或文件对话框。
有一种简单的方法吗?
private void buttonApply_Click (object sender, EventArgs e) {
try {
// ...
await executeAsync (_cts.Token, progress);
} catch (OperationCanceledException) { }
// ...
}
private async Task executeAsync (CancellationToken cancellationToken, IProgress<string> progress) {
// ...
await Task.Run (() => execute (path, cancellationToken, progress), cancellationToken);
}
private void execute (string path, CancellationToken cancellationToken, IProgress<string> progress) {
// do some work, report progress, check for cancellation
// --> depending on initial work, request additional input via UI thread, how?
// do more work, based on initial work and requested input
}
答案 0 :(得分:2)
感谢您的评论,他们为我指明了正确的方向。我研究了System.Progress<T>
的实现,我认为,我将从那里开始。
System.Progress<T>
捕获SynchronizationContext
,而Report(T value)
调用同步上下文的异步Post()
方法。
由于我需要调用的反馈,因此我将采用同步Send()
方法,并且大概基于新的接口ICallbackQuery<T, TResult>
或类似的IProgress<T>
和Progress<T>
答案 1 :(得分:0)
有一个名为ReactiveUI的框架-它使用ReactiveExtensions和Observables使MVVM的生活更轻松。
您无需深入研究并使用整个框架,但是它具有Interaction的简洁概念:
public class ViewModel : ReactiveObject
{
private readonly Interaction<string, bool> confirm;
public ViewModel()
{
this.confirm = new Interaction<string, bool>();
}
public Interaction<string, bool> Confirm => this.confirm;
public async Task DeleteFileAsync()
{
var fileName = ...;
// this will throw an exception if nothing handles the interaction
var delete = await this.confirm.Handle(fileName);
if (delete)
{
// delete the file
}
}
}
public class View
{
public View()
{
this.WhenActivated(
d =>
{
d(this
.ViewModel
.Confirm
.RegisterHandler(
async interaction =>
{
var deleteIt = await this.DisplayAlert(
"Confirm Delete",
$"Are you sure you want to delete '{interaction.Input}'?",
"YES",
"NO");
interaction.SetOutput(deleteIt);
}));
});
}
}
您可以只关注交互。
我还建议使用ReactiveCommand以避免按钮和异步操作出现问题。