在(Android)应用程序中,在用户与界面交互时加载和构建 ListView 是很常见的。然而,在 Winforms 中,趋势似乎是单击按钮并等待结果完全加载,然后用户才能继续浏览应用程序。
由于我当前使用的数据库访问速度相当慢,我想在异步方法中使用数据库,以使用户能够在数据未完全加载和显示的情况下保持与界面交互。
例如,我想在 Form_Load 事件中启动一个异步方法以继续收集数据。当此方法完成时,我想将数据绑定到某些控件 - 这(目前)根本不会改变功能。因此,我希望用户在处理应用程序时不要注意到任何差异(除了显示或不显示数据)。
我应该在哪里放置await关键字来完成这个任务?我无法将其放入我的 Load 事件中,因为这需要完成才能使应用程序“正常”运行。
是否有可能使用异步方法让 Windows 窗体完全反应,而并非所有方法都已完成,或者我是否出于我的目的而查看“错误”功能?
提前谢谢您。
编辑:根据 Srirams 的提示,我将加载事件本身设置为异步子,效果很好。这是一些简单的示例代码,显示了所需的行为:
Public Class DelayedLoadingWindow
Private Async Sub DelayedLoadingWindow_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim awaitedResultOne As Task(Of String) = GetDataOneAsync()
Label1.Text = Await awaitedResultOne
Dim awaitedResultTwo As Task(Of String) = GetDataTwoAsync()
Label2.Text = Await GetDataTwoAsync()
Dim awaitedResultThree As Task(Of String) = GetDataThreeAsync()
Label3.Text = Await GetDataThreeAsync()
Me.Text = "DONE"
End Sub
Public Async Function GetDataOneAsync() As Task(Of String)
Await Task.Delay(2000)
Return "Async Methods"
End Function
Public Async Function GetDataTwoAsync() As Task(Of String)
Await Task.Delay(2000)
Return "are"
End Function
Public Async Function GetDataThreeAsync() As Task(Of String)
Await Task.Delay(2000)
Return "running!"
End Function
End Class
我应该在哪里放置await关键字来完成这个任务?我 无法将其放入我的 Load 事件中,因为这需要完成 应用程序表现“正常”。
为什么不能在加载事件处理程序中等待?如果您使用
async
修饰符标记该方法,则可以做到这一点。
private async void Form_Load(object sender, EventArgs e)
{
//Do something
var data = await GetDataFromDatabaseAsync();
//Use data to load the UI
}
这样,您可以保持 UI 响应,并异步执行耗时的工作。
GetDataFromDatabaseAsync
必须是异步的(不应阻塞调用线程)。
如果这不能回答您的问题,请更具体。
我喜欢使用后台工作人员的概念,但有一个限制,即在后台线程中执行的任何行为在不使用调度程序的情况下都无法更新用户界面。
因此,在按钮单击处理程序中,我的处理如下:
/// <summary>
/// Handles Button click event to populate a data grid async
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnSubmit_Click(object sender, EventArgs e)
{
btnSubmit.Enabled = false;
dataGridView1.Visible = false;
lbStatus.Text = "Getting Search History ...";
var worker = new BackgroundWorker();
worker.DoWork += Worker_DoWork;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
接下来的任务是从数据库中获取数据并 将其内容存储在绑定到 DataGridView 控件的 List 对象中。
/// <summary>
/// Fetch data from remote data source on store in IList
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
_vwlist.Clear();
_vwlist.AddRange(GetHistory());
e.Result = true;
}
完成后处理用户界面交互。
/// <summary>
/// Handles data-binding and user interface state after data completion.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
dataGridView1.DataSource = _vwlist;
btnSubmit.Enabled = true;
dataGridView1.Visible = true;
lbStatus.Text = "Ready";
}
您可以使用BackgroundWorker Control,
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx
您只需将BackgroundWorker Control放在表单上(在我们的例子中为backgroundWorker1),BackgroundWorker Control还支持取消、RunWorkerCompleted等。
private SlowLoadingForm frm;
private void startAsyncButton_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
frm = new SlowLoadingForm();
frm.show();
Application.Run(frm);
}