如何在 C# / WPF 中检查线程是否完成,然后填充进度条

发布于 2024-08-22 10:10:00 字数 513 浏览 5 评论 0 原文

我正在开发我的第一个 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;
}

I am just working on my first GUI application on Windows.

I have a WPF GUI to a small C# utility which copies files. When the button is clicked to copy, I obviously don't want the GUI to hang. So, I fire off a new thread to run the method which copies the files. I assume I'm on track so far and there's no "better" way of doing it in C#?

Now, I have a ProgressBar which I want to appear filled when the thread is done. (It's fine running as indeterminate for now). How do I check when the copying is done?

So, so far I have:

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

t.Start();

PBar.IsIndeterminate = true;

And I want something after that that works like:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

我不在是我 2024-08-29 10:10:01

Have a look at the BackgroundWorker class. It supports events like RunWorkerCompleted or ProgressChanged.
Have a look here, too (this is about threading in general + backgroundworker, again).

韬韬不绝 2024-08-29 10:10:01

如前所述,请考虑使用 BackgroundWorker班级。它是针对这些情况而设计的,并公开适合您想要完成的任务的事件。

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

As already stated, consider the use of the BackgroundWorker class. It was designed for these situations and exposes events suited for what you are trying to accomplish.

Use the ProgressChangedevent to report progress incrementally and the RunWorkerCompleted for when the task finishes. Check the MSDN page for code samples.

神经暖 2024-08-29 10:10:01

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

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

Wrap the if (t.Done) block in its own method. Invoke this method from the end of your worker thread.

Also, you might want to give the worker thread a name to make it easier to spot in the debugger.

巡山小妖精 2024-08-29 10:10:01

您需要一个回调方法。 应该可以帮助您入门。它使用 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);

You need a callback method. This should get you started. It uses an AsyncCallback, which is the best way to tackle this type of issue.

I just looked up an example I've been using for a project and stripped out the code specific to my app:

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);
面犯桃花 2024-08-29 10:10:01

快速而简单的破解方法是在线程中的匿名方法末尾更新 UI。显然你不能直接更新它,但你可以使用Dispatcher.Invoke

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

t.Start();

The quick and easy hack would be to just update the UI at the end of your anonymous method in your thread. Obviously you can't update it directly, but you can use Dispatcher.Invoke:

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

t.Start();
风情万种。 2024-08-29 10:10:01

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

在 Windows 窗体中,完成此操作的方式是通过实现 控件上的“ISynchronizeInvoke 接口”< /a> 类,主要通过执行调用方法

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

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

因此,无论 Windows 窗体是环境还是 WPF,都可以在这些上下文中以相同的方式进行一次调用,从而获得相同的效果(封送调用)。

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

// 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 线程,而无需等待该调用完成。

As a general Windows programming principal, you have to make calls to update the UI from the UI thread (the one that is processing messages through a message pump).

In Windows Forms, the way that this was done was through the implementation of the ISynchronizeInvoke interface on the Control class, primarily through the implementation of the Invoke method.

With the release of .NET 2.0, it was realized that a better mechanism was needed to marshal calls into the correct context. That's where the SynchronizationContext comes in.

This class abstracts the interface you would use for marshaling calls to different contexts, allowing for specific implementations depending on the context.

So whether or not Windows Forms is the environment, or WPF, one call can be made in the same way across those contexts with the same effect (marshaling the call).

In your particular case, because you are using a closure (anonymous method), you can take advantage of the fact that a SynchronizationContext is available to you (through the static Current property) at the invocation site of the Thread to provide the mechanism to call back to the UI thread from your background thread:

// 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(); 

Note, if you don't care about waiting for the result of the call back to the UI thread, you can make a call to the Post method instead, which will dispatch the call to the UI thread without waiting for that call to complete.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文