【问题标题】:Updating a progress bar in a C# GUI from another thread and class [duplicate]从另一个线程和类更新 C# GUI 中的进度条 [重复]
【发布时间】:2012-05-30 11:43:07
【问题描述】:

可能重复:
Updating a Progress Bar from Another Thread

在我的程序中,我想将非 GUI 功能分离到另一个类中,并将与 GUI 相关的东西留在主类中。但是,当工人类中的一种工人方法正在执行其工作时,我在更新进度条时遇到了问题。我知道我将不得不在这里使用多线程,但我不明白如何。我可能只是遗漏了一些简单的东西,但是当我查找有关它的信息时,似乎大多数教程都在谈论细节,但并没有很好地解释大局。我部分了解什么是调用和委托命令,但我并不真正了解它们是如何交互的。

下面是我想做的精简版。如何修改它以更新进度条,但保持窗口响应和重新绘制?

主窗体类:

public partial class Form1 : Form
{
    time_waster thing = new time_waster();

    public Form1()
    {
        InitializeComponent();
        progressBar1.Minimum = 0;
        progressBar1.Maximum = 100;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        thing.something_that_takes_a_while();
    }
}

单独的工人阶级: 上课时间浪费 { 公共时间浪费者() { }

    public void something_that_takes_a_while()
    {
        int delay = 200;
        for (int i = 0; i < 100; i++)
        {
            Thread.Sleep(delay);
            //appropriate code to update the progress bar for each iteration of the for loop.
        }
    }
}

【问题讨论】:

  • 使用委托和调用方法来更新 UI 控件。

标签: c# multithreading progress-bar


【解决方案1】:

.NET 包含一个名为BackgroundWorker 的类,它提供了用于报告事件中后台线程进度的方法。该事件会在创建 BackgroundWorker 的线程(通常是 UI 线程)上自动调用。

订阅该“ProgressChanged”事件,并更新该事件处理程序中的进度条。 MSDN 官方文档提供了一些示例代码。

【讨论】:

    【解决方案2】:
    MethodInvoker mi = new MethodInvoker(() => progressBar.Value= newProgressValue);
    if (progressBar.InvokeRequired)
    {
        progressBar.Invoke(mi);
    }
    else
    {
        mi.Invoke();
    }
    

    此代码属于冗长的任务。见:

    1. InvokeRequired
    2. Invoke
    3. Delegates

    Lambda 只是一个过分花哨的词,用于内联声明的函数(或方法),而不是作为类上的方法或支持它们的语言中的原始函数。如果您不将其分配给命名变量,则它是“匿名的”。要小心,因为它们“捕获”了它们所需的变量,如果你不理解它们,它们的行为可能会有点奇怪。

    lambda 的语法非常简单:() =&gt; someValue;public void SomeMethod() { return someValue; } 几乎相同,将内容放入括号中以向 lambda 添加参数。如果您只有一个参数,请随意跳过括号。

    【讨论】:

    • 所以,我对如何使用它有点困惑。这是在我的方法中完成冗长的任务,还是在我的主要方法中?另外,我不确定我是否完全理解那里的 if/else 块的作用。如果我明白,它正在验证调用是来自当前线程还是来自不同的线程,对吗?另外,我发现“ () => proressBar.Progress... ”被称为 Lambda 表达式,它是“匿名代表的简写”,但这是什么意思,为什么我需要它?
    • 我还是很困惑。如果进度条在我的主类中,而工作线程在另一个类中,如果它在冗长的任务中,这个调用将如何工作?这似乎应该在主类中,因为它仍然具有正确的范围。我是否必须在主类中调用某个中间类,然后调用其他类中的冗长任务?
    【解决方案3】:
       static main()
        {
             Thread th = new Thread(calling_function);
             th.start();  
        }
    
    
        calling_function()
        {
            //do your work;
            MethodInvoker m = new MethodInvoker( ()=> progressbar.Progress=value);
            progressbar.Invoke(m);
        }
    

    【讨论】:

    • 好的,现在开始工作,说calling_function()必须在进度条超出范围的不同类中,我将如何访问它,或者我将如何传回让我的 GUI 读取以访问它的东西?
    • @Xantahm 你必须必须将引用传递给calling_function()
    • @Md:你真的应该在这里使用真正的 C#。
    • 如果 GUI 和 call_function 在不同的类中,则使用类对象。示例 GUI_class obj=new GUI_class(); obj.progressbar.invoke(m);如果您需要更多说明,请询问。
    • 我已尝试将其作为参考传递,但它不接受该命令。 Thread th = new Thread(other_class.calling_function(ref progressBar1)) 没有通过,它抱怨不正确的参数(当我定义调用函数(ref ProgressBar ProgressBar1)时)。其他资源说将参数放入 th.Start() 部分,所以我尝试了 Thread th = new Thread(Other_function.calling function); th.Start(参考 ProgressBar1)。这也行不通。为什么它不接受参数?
    猜你喜欢
    • 2011-08-12
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多