繁体   English   中英

如何检查线程,然后填写C#/ WPF中的进度条

[英]How to check a thread is done, then fill progress bar in C# / WPF

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

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

现在,我有一个ProgressBar ,我希望在线程完成时显示它。 (现在它运行良好,不确定)。 如何检查复制何时完成?

所以,到目前为止,我有:

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

t.Start();

PBar.IsIndeterminate = true;

之后我想要的东西就像:

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

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

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

使用ProgressChanged事件以递增方式报告进度,并在任务完成时使用RunWorkerCompleted 检查MSDN页面以获取代码示例。

你需要一个回调方法。 应该让你开始。 它使用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);

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

此外,您可能希望为工作线程指定一个名称,以便更容易在调试器中找到它。

快速简单的黑客就是在线程中的匿名方法结束时更新UI。 显然你无法直接更新它,但你可以使用Dispatcher.Invoke

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

t.Start();

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

在Windows窗体中,完成此操作的方式是通过在Control类上实现ISynchronizeInvoke接口 ,主要通过实现Invoke方法

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

此类抽象出用于编组调用不同上下文的接口,允许根据上下文进行特定实现。

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

在您的特定情况下,因为您正在使用闭包(匿名方法),您可以利用在Thread的调用站点上可以使用SynchronizationContext(通过静态Current属性 )来提供调用的机制。从后台线程返回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方法 ,这将调用UI线程而不等待该调用完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM