【问题标题】:How to check a thread is done, then fill progress bar in C# / WPF如何检查线程是否完成,然后在 C#/WPF 中填充进度条
【发布时间】:2010-02-18 16:20:28
【问题描述】:

我正在开发我在 Windows 上的第一个 GUI 应用程序。

我有一个用于复制文件的小型 C# 实用程序的 WPF GUI。单击按钮进行复制时,我显然不希望 GUI 挂起。所以,我启动了一个新线程来运行复制文件的方法。我认为到目前为止我已经步入正轨,并且在 C# 中没有“更好”的方式来做到这一点?

现在,我有一个ProgressBar,希望在线程完成后显示为已填充。 (现在可以不确定地运行)。如何检查复制完成时间?

所以,到目前为止我有:

Thread t = new Thread(delegate() 
{ 
    po.Organise(inputPath, outputPath, recursive); 
});

t.Start();

PBar.IsIndeterminate = true;

然后我想要一些类似的东西:

if (t.Done)
{
    PBar.Value = 100;
}

【问题讨论】:

标签: c# wpf multithreading progress-bar


【解决方案1】:

看看BackgroundWorker 类。它支持RunWorkerCompletedProgressChanged 等事件。
也看看here(这又是关于一般的线程+后台工作者)。

【讨论】:

【解决方案2】:

如前所述,考虑使用BackgroundWorker 类。它专为这些情况而设计,并公开适合您要完成的事情的事件。

使用ProgressChangedevent 逐步报告进度,使用RunWorkerCompleted 报告任务何时完成。查看 MSDN 页面以获取代码示例。

【讨论】:

    【解决方案3】:

    if (t.Done) 块包装在自己的方法中。从工作线程的末尾调用此方法。

    此外,您可能希望为工作线程命名,以便在调试器中更容易发现。

    【讨论】:

      【解决方案4】:

      你需要一个回调方法。 This 应该可以帮助您入门。它使用 AsyncCallback,这是解决此类问题的最佳方法。

      我刚刚查找了一个我一直用于项目的示例,并删除了特定于我的应用程序的代码:

      System.Windows.Forms.MethodInvoker mi = new System.Windows.Forms.MethodInvoker(delegate()
      {
          // Do your file copy here
      });
      
      AsyncCallback ascb = new AsyncCallback(delegate(IAsyncResult ar)
      {
          this.Dispatcher.Invoke(new ThreadStart(delegate (){
          // set progressbar value to 100 here
          }), null);
      });
      
      mi.BeginInvoke(ascb, null);
      

      【讨论】:

        【解决方案5】:

        快速简便的破解方法是在线程中的匿名方法结束时更新 UI。显然不能直接更新,但是可以使用Dispatcher.Invoke

        Thread t = new Thread(delegate() 
        { 
            po.Organise(inputPath, outputPath, recursive); 
            Dispatcher.Invoke(new Action(()=>{PBar.Value = 100;}),null);
        });
        
        t.Start();
        

        【讨论】:

          【解决方案6】:

          作为一般的 Windows 编程主体,您必须从 UI 线程(通过消息泵处理消息的线程)调用以更新 UI。

          在 Windows 窗体中,这样做的方式是通过在 Control 类上实现 ISynchronizeInvoke interface,主要是通过实现 Invoke method

          随着 .NET 2.0 的发布,人们意识到需要一种更好的机制来将调用编组到正确的上下文中。这就是SynchronizationContext 的用武之地。

          这个类抽象了您将用于封送对不同上下文的调用的接口,允许根据上下文进行特定的实现。

          因此,无论 Windows 窗体是环境还是 WPF,都可以在这些上下文中以相同的方式进行一次调用,并具有相同的效果(编组调用)。

          在您的特定情况下,由于您使用的是闭包(匿名方法),因此您可以利用在线程的调用站点上可以使用 SynchronizationContext 的事实(通过静态Current property)提供从后台线程回调 UI 线程的机制:

          // Get the synchronization context.
          // This is in the UI thread.
          SynchronizationContext sc = SynchronizationContext.Current;
          
          // Create the thread, but use the SynchronizationContext
          // in the closure to marshal the call back.
          Thread t = new Thread(delegate()  
          {  
              // Do your work.
              po.Organise(inputPath, outputPath, recursive);  
          
              // Call back using the SynchronizationContext.
              // Can call the Post method if you don't care
              // about waiting for the result.
              sc.Send(delegate()
              {
                  // Fill the progress bar.
                  PBar.Value = 100;
              });
          }); 
          
          // Make the progress bar indeterminate.
          PBar.IsIndeterminate = true;
          
          // Start the thread.
          t.Start(); 
          

          注意,如果您不关心等待 UI 线程的回调结果,您可以改为调用 Post method,它会在不等待的情况下将调用分派给 UI 线程调用完成。

          【讨论】:

            猜你喜欢
            • 2012-01-28
            • 2011-02-15
            • 1970-01-01
            • 2016-06-23
            • 2011-07-27
            • 1970-01-01
            • 2019-02-16
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多