如何异步调用长时间运行的方法并在 UI 上显示等待图像






2.50/5 (5投票s)
本文档解释了如何异步调用耗时较长的函数,并在 UI 上显示等待图像。
引言
本文档描述了如何在单独线程中异步调用耗时较长的函数,并在线程完成任务之前显示等待图像。
背景
在开发过程中,经常会遇到需要运行耗时较长的函数/方法/编程逻辑的情况。在这种情况下,始终建议在单独线程中异步运行它,并向最终用户显示等待消息/图像。这个示例应用程序将解释如何实现这一点。
Using the Code
首先,我在 Form1
类中声明了两个委托。LoadDataDelegate
用于异步调用耗时较长的函数,它接受一个键作为参数(仅用于演示参数化示例)。DisplayWaitDelegate
用于显示/隐藏等待图像。它接受一个布尔参数来设置是显示还是隐藏。
//declare a delegate to run the Load method in a separate thread
delegate void LoadDataDelegate(string key);
//declare a delegate to call the Display Wait method
delegate void DisplayWaitDelegate(bool boolDisplay);
以下代码位于我的“加载数据”按钮单击事件中。我稍后会解释 DisplayWait
函数,但它用于显示等待图像。Class1
中的“LoadData
”函数执行时间较长,因此我实例化了 LoadDataDelegate
委托并将此函数名传递给它。最后,调用 BeginInvoke
开始执行。请注意第二个参数,即函数名(稍后解释),在异步调用/线程完成时被调用。
private void btnLoadData_Click(object sender, EventArgs e)
{
//will be calling the long running methid, so diaplay the wait image
DisplayWait(true);
string key = textBox1.Text;
Class1 objClass1 = new Class1();
//Create an instance of the Load delegate and pass in the Function Name
LoadDataDelegate delLoadData = new LoadDataDelegate(objClass1.LoadData);
//Since we want to call the Load function
//asynchronously on another thread, use BeginInvoke. The next
//argument is the function name being called once this thread is completed
delLoadData.BeginInvoke(key, this.LoadComplete, delLoadData);
}
以下是 LoadComplete
函数的代码。此函数获取委托的句柄并调用 EndInvoke
方法来停止异步调用。再次调用 DisplayWait
函数,但这次布尔参数的值为 false
,这将隐藏等待图像。
private void LoadComplete(IAsyncResult ar)
{
LoadDataDelegate d = (LoadDataDelegate)ar.AsyncState;
//end the Load method call
d.EndInvoke(ar);
//now when the Load is complete..remove the wait image
DisplayWait(false);
MessageBox.Show("Data Load Completed.");
}
以下是 DisplayWait
函数的代码。pcitureBox1
控件包含等待图像。需要调用 InvokeRequired
来确保此程序不会导致跨线程异常。再次,创建 DisplayWaitDelegate
的实例并将相同的函数名“DisplayWait”传递给它。然后调用控件(在本例中为 pictureBox1
)的 Invoke
方法,并将委托实例和参数作为 object
数组传递(在本例中,只有一个参数)。
现在,这将再次调用 DisplayWait
函数,并且这次它将进入 else
块,在那里我设置可见性。我还将 UseWaitCursor
属性设置为 Form
级别,以便在显示等待图像时显示沙漏光标。
private void DisplayWait(bool boolDisplay)
{
//this check is required to carry out the cross thread
//oprtation on a control which is pictureBox1 in this case.
if (pictureBox1.InvokeRequired)
{
// this is worker thread
DisplayWaitDelegate del = new DisplayWaitDelegate(DisplayWait);
pictureBox1.Invoke(del, new object[] { boolDisplay });
}
else
{
// this is UI thread
pictureBox1.Visible = boolDisplay;
UseWaitCursor = boolDisplay;
}
}
最后,Class1
中的“LoadData
”函数,它只是 Thread.Sleep(10000)
,用于显示此应用程序的 10 秒延迟示例。
//long running method
public void LoadData(string key)
{
// The actual method imlementation
//just for sample delay added the sleep for 10 seconds
Thread.Sleep(10000);
}
关注点
这也可以扩展为显示进度条。
历史
- 版本 1.0:2008/08/22。