65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.50/5 (5投票s)

2008年8月15日

CPOL

2分钟阅读

viewsIcon

48503

downloadIcon

678

本文档解释了如何异步调用耗时较长的函数,并在 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。
© . All rights reserved.