2014-06-19 39 views
0

在wpf应用程序 - 用户界面变得冻结按钮点击 - 那么如何显示繁忙的指标,而庞大的数据处理?如何在长时间运行过程中显示繁忙指示符?

我已经尝试了后台工作进程,但它抛出了下面的异常。

消息中的 “调用线程” 是不是你的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; 
     } 
    } 

请做要紧..

感谢和问候, 维杰Babu

+0

显示一些代码,具体与您的问题 – Nitin

+0

回答

-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(); 
+0

-1虽然这可能是您最终使用的解决方案,但这是一个非常糟糕的解决方案。 System.Threading.Thread类不再直接在.NET中直接使用,因为它已被替换为Task类和.NET 4.5,await和async关键字。 – Sheridan

+0

我同意你的意见。 .NET 4.5的许多功能已经改为任务,而BackgroundWorker现在都已经过时了。但是我在一些项目中一直在研究.NET 4.0,所以我使用了这些类/方法。 –

+0

As @Sheridan表示Task类可以在.Net 4中使用。 – Dzyann

-1

试试这个:

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

为什么downvote?这个代码的工作原理和我见过很多的地方(这里也是如此),当涉及到背景工作者和更新UI时,它的工作... – Eirik

+0

-1对不起,我通常发表评论。我下调了你的答案,因为你没有提供何时何地应该调用这个内容。此外,也不必调用“调度程序”。Invoke'将'Visibility'设置为'Visible',因为在启动'BackgroundWorker'之前应该完成*,而执行仍然在UI线程上。我接受你的调用并不像问题作者对'Dispatcher.Invoke'的调用那样毫无意义,但都是一样的,它不是必需的。 – Sheridan

+0

谢谢您的解释和代码建议!我已经编辑了代码 - 1.在开始新线程之前执行UI工作2.创建新线程,启动它。 3.完成工作,将结果发送到UI线程... –

0

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

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

We cannot call any functions on any UI objects from any other thread than the UI thread

牢记这一点,这意味着我们不能设置任何忙指标的Visiblity从后台线程。所以,最简单的解决方法是之前将其设置为Visibility.Visible开始BackgroundWorker

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

正如我们从二OOO页面请参阅MSDN上:

You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events.

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

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

由于它运行在UI线程上,没有必要打电话给Dispatcher.Invoke,而且值得注意的是,您的来电此方法不执行任何操作,因为你没有提供任何委托方法来运行它:

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