如何在长时间进程运行时显示忙碌指示器?

时间:2014-06-19 10:06:23

标签: wpf

在wpf应用程序中 - 按钮点击后UI被冻结 - 然后如何在大量数据处理时显示忙指示符?

我已尝试过后台工作程序,但它抛出了以下异常。

"调用线程"在消息中不是你的UI线程......

示例代码:

    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle);

        BackgroundWorker worker = sender as BackgroundWorker;
        this.busyIndicator.Visibility = Visibility.Visible;
        busyIndicator.IsBusy = true;

        for (int k = 1; (k <= 10); k++)
        {
            if ((worker.CancellationPending == true))
            {
                e.Cancel = true;
                break;
            }
            else
            {
                int intAutomationID = 0;
                int intAutomation_SS_ID = 0;
                int intAS_ID = 0;
                string strProcedureName = "";
                //busyIndicator.Visibility = Visibility.Visible;
                try
                {

                    // Insert entry into AUTOMATION_PROCESS table.
                    intAutomationID = Pkg_TargetsIdentifiers.InsertAutomationProcess(Convert.ToInt32(cmbIdentifier.SelectedValue),
                        Convert.ToInt32(cmbSourceData.SelectedValue), "InProgress", 0, "Insert");

                    if (intAutomationID > 0)
                    {
                        for (int i = 0; i <= dgvProcessLists.Items.Count - 1; i++)
                        {
                            int j = 3;
                            strProcedureName = "";
                            strProcedureName = (dgvProcessLists.Items[i] as DataRowView).Row.ItemArray[j].ToString();
                            if (!string.IsNullOrEmpty(strProcedureName))
                            {

                                //AS_ID
                                // InitializeMouseHandlersForVisual(dgvProcessLists);
                                intAS_ID = Convert.ToInt32((dgvProcessLists.Items[i] as DataRowView).Row.ItemArray[0].ToString());

                                intAutomation_SS_ID = Pkg_TargetsIdentifiers.InsertAutomationStepsStatus(intAS_ID, intAutomationID,
                                 "Inprogress", 0, "Insert");

                                bool boolStatus = Pkg_TargetsIdentifiers.CallActionProcess(strProcedureName, intAutomationID);
                                if (boolStatus == true)
                                {
                                    //var selectedRow = DataProcessing.Class1.GetSelectedRow(this.dgvProcessLists);
                                    //var columnCell = DataProcessing.Class1.GetRow(this.dgvProcessLists,0);


                                    intAutomation_SS_ID = Pkg_TargetsIdentifiers.InsertAutomationStepsStatus(intAS_ID, intAutomationID,
                                     "Completed", intAutomation_SS_ID, "Update");
                                    intAS_ID = 0;
                                    strProcedureName = "";
                                    DataRowView row = (dgvProcessLists.Items[i] as DataRowView);
                                    if (row != null)
                                    {
                                        if (row.DataView.Table.Columns.Contains("Status"))
                                        {
                                            Type type = row["Status"].GetType();
                                            string status = row["Status"] == System.DBNull.Value ? null : (string)row["Status"];


                                            if (boolStatus == true)
                                            {
                                                Uri uri = new Uri("pack://application:,,,/Images/green.jpg");
                                                BitmapImage source = new BitmapImage(uri);


                                            }
                                            if (boolStatus == false)
                                            {
                                                Uri uri = new Uri("pack://application:,,,/Images/red.jpg");
                                                BitmapImage source = new BitmapImage(uri);

                                            }
                                        }
                                    }
                                    continue;
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                        intAutomationID = Pkg_TargetsIdentifiers.InsertAutomationProcess(Convert.ToInt32(cmbIdentifier.SelectedValue),
                        Convert.ToInt32(cmbSourceData.SelectedValue), "Completed", intAutomationID, "Update");

                    }

                    // Perform a time consuming operation and report progress.
                    System.Threading.Thread.Sleep(500);
                    worker.ReportProgress((k * 10));
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                { }
            }
        }
    }
    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle);

        if ((e.Cancelled == true))
        {
            this.busyIndicator.Visibility = Visibility.Hidden;
            busyIndicator.IsBusy = false;
        }

        else if (!(e.Error == null))
        {
            this.busyIndicator.Visibility = Visibility.Hidden;
            busyIndicator.IsBusy = false;
        }

        else
        {
            this.busyIndicator.Visibility = Visibility.Hidden;
            busyIndicator.IsBusy = false;
        }
    }
    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.busyIndicator.Visibility = Visibility.Visible;
        busyIndicator.IsBusy = true;
    }

    /// <summary>
    ///  btnStartProcess_Click
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnStartProcess_Click(object sender, RoutedEventArgs e)
    {
        try
        {
        if (bw.IsBusy != true)
        {
            bw.RunWorkerAsync();
        }

            //worker.RunWorkerAsync();
        //    //};

        //    //worker.RunWorkerCompleted += (o, ea) =>
        //    //{
        //    //    busyIndicator.Visibility = Visibility.Hidden;
        //    //    busyIndicator.IsBusy = false;
        //    //};

        //    //worker.RunWorkerAsync();
        //    //};
        //    //worker.RunWorkerAsync();

        //bw.RunWorkerCompleted += (o, ea) =>
        //{
        //    busyIndicator.IsBusy = false;
        //    busyIndicator.Visibility = Visibility.Hidden;
        //};
        //busyIndicator.IsBusy = true;
        //busyIndicator.Visibility = Visibility.Visible;
        //bw.RunWorkerAsync();
        }
        catch (Exception ex)
        {

            throw ex;
        }
    }

请做必要的..

谢谢和问候, Vijay Babu

3 个答案:

答案 0 :(得分:1)

首先,您需要让BackgroundWorker代码正常运行。为此,我建议您查看我对How to correctly implement a BackgroundWorker with ProgressBar updates?问题的回答,该问题提供了一个清晰,简洁的代码示例。

我现在假设您已正确设置BackgroundWorker,因此我们可以继续显示忙碌指示符。首先,您需要了解错误的原因:

  

我们不能从UI线程之外的任何其他线程调用任何UI对象上的任何函数

考虑到这一点,这意味着我们无法从后台线程设置任何忙指标的Visiblity。因此,最简单的解决方法是在开始Visibility.Visible之前将其设置为BackgroundWorker

busyIndicator.Visibility = Visibility.Visible;
busyIndicator.IsBusy = true;
backgroundWorker.RunWorkerAsync();

我们可以从MSDN上的ooo页面看到:

  

您必须小心不要操纵DoWork事件处理程序中的任何用户界面对象。而是通过ProgressChangedRunWorkerCompleted事件与用户界面进行通信。

这基本上意味着我们可以在UI线程上处理这些事件,因此我们可以从这些事件处理程序访问我们的UI元素。因此,当您的长时间运行过程完成时,将调用RunWorkerCompleted事件。如果您处理此事件,则可以在相关事件处理程序中隐藏繁忙指示符:

private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    busyIndicator.Visibility = Visibility.Hidden;
    busyIndicator.IsBusy = false;
}

当它在UI线程上运行时,不需要调用Dispatcher.Invoke,并且值得注意的是,您对此方法的调用不执行任何操作,因为您没有提供任何委托方法来运行它: / p>

Dispatcher.Invoke(new Action(() => { /*No action*/ }), DispatcherPriority.ContextIdle);

答案 1 :(得分:-1)

试试这个:

Dispatcher.Invoke(() => { busyIndicator.Visibility = Visibility.Visible; });

答案 2 :(得分:-1)

{

        System.Threading.ThreadStart start = delegate()
        {
            CallAutomationProcess();
            //done doing work, send result to the UI thread
            Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                new Action(changest));

        };
        this.busyIndicator.IsBusy = true;
        this.busyIndicator.Visibility = Visibility.Visible;

        new System.Threading.Thread(start).Start();