2009-07-28 27 views
9

我正在使用C#和WPF,两者都很新颖。如何在繁忙循环中显示进度?

我有一个循环,从外部来源读取大量的数据。该过程大约需要20秒,我想向用户显示进度。我不需要任何花哨的进度条,所以我选择在标签中绘制我的进度,标签上会显示“Step 1/1000”,然后更改为“Step 2/1000”等。

我的代码看起来像这个:

// "count" is the number of steps in the loop, 
// I receive it in previous code 

String countLabel = "/"+count.ToString(); 

for (i = 0; i < count; i++) 
{ 
    ... do analysis ... 
    labelProgress.Content = "Step "+i.ToString()+countLabel 
} 

但是,在分析过程中,屏幕“卡住”,进度不显示为前进。我理解我在C++中的这种行为,我可能会有一个单独的线程显示进度条从循环接收通知,或某种形式的重绘/刷新,或强制窗口/应用程序处理其消息队列。

什么是在C#中做到这一点的正确方法?我不依赖于标签,因此,如果有一个简单的进度条弹出画面,我可以代替使用这个标签也将是巨大的......

感谢

+0

这可能是帮助你,** 100%测试** http://stackoverflow.com/a/42995210/6863414 – 2017-04-06 03:53:08

回答

11

移动工作再上一个BackgroundWorker和使用ReportProgress方法。

for (i = 0; i < count; i++) 
{ 
    ... do analysis ... 
    worker.ReportProgress((100 * i)/count); 
} 

private void MyWorker_ProgressChanged(object sender, 
    ProgressChangedEventArgs e) 
{ 
    taskProgressBar.Value = Math.Min(e.ProgressPercentage, 100); 
} 
+0

是线程安全的吗? – 2009-07-28 15:10:42

+1

是的,应该是。您的后台工作人员只在一个线程中进度栏更新只在UI线程上。如果UI线程尝试更新值,则除UI线程之外的任何其他线程都会引发异常。所以你用这种方法保证线程安全。 – user7116 2009-07-28 15:13:03

2

由于当前线程的优先级高于最终设置标签的UI线程,所以UI未更新。所以,直到你的线程完成你的东西,它会最终更新你的标签。

我们是幸运的,对每一个WPF控件,可以让你启动一个新的线程与其他优先级的调度属性..

labelProgress.Dispatcher.Invoke(DispatcherPriority.Background, 
        () => labelProgress.Content = string.Format("Step {0}{1}", i, countLabel)); 

这火起来在后台线程,并会得到这份工作完成了!你也可以尝试其他DispatcherPriority选项

PS我也冒昧地添加一个匿名方法和解决您的字符串解析有点..希望你不介意..

3
//Create a Delegate to update your status button 
    delegate void StringParameterDelegate(string value); 
    String countLabel = "/" + count.ToString(); 
    //When your button is clicked to process the loops, start a thread for process the loops 
    public void StartProcessingButtonClick(object sender, EventArgs e) 
    { 
     Thread queryRunningThread = new Thread(new ThreadStart(ProcessLoop)); 
     queryRunningThread.Name = "ProcessLoop"; 
     queryRunningThread.IsBackground = true; 
     queryRunningThread.Start(); 
    } 

    private void ProcessLoop() 
    { 
     for (i = 0; i < count; i++) 
     { 
      ... do analysis ... 
      UpdateProgressLabel("Step "+i.ToString()+countLabel); 
     } 
    } 

    void UpdateProgressLabel(string value) 
    { 
     if (InvokeRequired) 
     { 
      // We're not in the UI thread, so we need to call BeginInvoke 
      BeginInvoke(new StringParameterDelegate(UpdateProgressLabel), new object[] { value }); 
      return; 
     } 
     // Must be on the UI thread if we've got this far 
     labelProgress.Content = value; 
    } 
相关问题