【发布时间】:2020-11-26 10:31:05
【问题描述】:
我有一个经典的 WinForms 应用程序,它与服务器 api 进行异步通信。这是通过异步等待模式实现的。
现在我遇到了“验证”事件的问题。我们将此事件用于客户端验证(检查输入是否为空)并设置取消。 如果输入有效,那么我将输入发送到服务器异步并等待结果。
这是我的问题。现在控制意味着它是有效的。当回调将取消事件设置为 false 时为时已晚。
这是我的代码:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public string CustomerName { get; set; }
private async void Button1_Validating(object sender, CancelEventArgs e)
{
if (CustomerName == null)
{
e.Cancel = true;
}
else
{
var isValidAndSaved = await SaveOnServerAsync(CustomerName);
// Here is the Problem: Setting e.Cancel in callback is too late.
if (isValidAndSaved)
{
e.Cancel = false;
}
else
{
e.Cancel = true;
}
}
}
/// <returns>True if the given model was valid and save operation was successfull.</returns>
public async Task<bool> SaveOnServerAsync(string customerName)
{
await Task.Delay(3000); // Send given customerName to server in real app.
return customerName.Contains("%") ? false : true;
}
}
我通过“等待”主线程中的任务来尝试使用经典编程(同步)。但后来我产生了死锁。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public string CustomerName { get; set; } = "3";
private void Button1_Validating(object sender, CancelEventArgs e)
{
if (CustomerName == null)
{
e.Cancel = true;
}
else
{
// Deadlock because MainThread waits for callback.
var isValidAndSaved = SaveOnServerAsync(CustomerName).Result;
if (isValidAndSaved)
{
e.Cancel = false;
}
else
{
e.Cancel = true;
}
}
}
/// <returns>True if the given model was valid and save operation was successfull.</returns>
public async Task<bool> SaveOnServerAsync(string customerName)
{
await Task.Delay(3000); // Send given customerName to server in real app.
return customerName.Contains("%") ? false : true;
}
}
有人想出一个好的模式吗?
如果我在等待异步任务之前将 Cancel 设置为 false,那么我的问题将是用户点击被丢弃并且用户体验足够。
【问题讨论】:
-
遗憾的是你必须让它同步
-
您知道如何使其同步吗?如果我尝试它,那么我的 GUI 线程将被冻结(参见第二个代码示例)。
-
是死锁还是阻塞?无论如何,
Validate事件是一个 UI 验证事件。您的第一张支票 (CustomerName) 是有效支票。另一个调用应该是Click事件。 -
在我们的应用程序中,无需按钮即可调用保存命令。当表单失去焦点时保存发生。目标是用户在表单中被捕获,只要它未被保存或中止。表单不在单独的窗口上,而是在与其他表单和网格的停靠元素上。
-
恕我直言,您在滥用
Validating事件。它旨在验证,而不是提交更改。
标签: c# .net winforms async-await