2012-05-23 67 views
2

可能重复:
Updating a Progress Bar from Another Thread更新在C#GUI一个进度条,从另一个线程和类

在我的计划,我想非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(); 
    } 
} 

单独的工作类: 类time_waster { 公共time_waster() { }

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. 
     } 
    } 
} 
+0

使用委托和调用方法来更新UI上的控件。 –

回答

6

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

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

4
MethodInvoker mi = new MethodInvoker(() => progressBar.Progress = newProgressValue); 
if (progressBar.InvokeRequired) 
{ 
    progressBar.Invoke(mi); 
} 
else 
{ 
    mi.Invoke(); 
} 

此代码属于在冗长的任务。请参阅:

  1. InvokeRequired
  2. Invoke
  3. Delegates

拉姆达只是一个过度花哨的词的功能(或方法)声明为内联,而不是作为类或方法作为支持它们的语言的原始功能。如果你不把它分配给一个指定的变量,它就是“匿名的”。要小心,因为他们“捕获”它们所需的变量,如果你不了解它们,可能会有点奇怪。

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

+0

所以,我对如何使用这个有点困惑。这会在我的方法中完成冗长的任务,还是在我的主要任务中?另外,我不确定我完全理解if/else块在做什么。如果我明白了,它正在验证调用是来自当前线程还是其他线程是否正确?此外,我发现“()=> proressBar.Progress ...”被称为Lambda表达式,并且它是“匿名代理的简写”,但这意味着什么,为什么我需要它? – Xantham

+0

我还是很困惑。如果进度条在我的主类中,并且工作线程在另一个类中,那么如果它在冗长的任务中,这将如何调用?这看起来应该在主类中,因为它仍然有正确的范围。我是否必须让这个电话在主要班级中进行一些中间班级,然后又在另一班级中调用冗长的任务? – Xantham

1
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); 
    } 
+0

好吧,现在将一个扳手放入作品中,并说call_function()必须位于不同范围的进度条超出范围的类中,我将如何访问它,或者如何返回某些内容以供我的GUI读取访问它? – Xantham

+0

@Xantahm你必须*将一个引用传递给'calling_function()'。 – Crisfole

+0

@Md:你真的应该在这里使用真正的C#。 – Crisfole