2011-04-04 32 views
6

我有后续的按钮单击事件:C# - 代码处理顺序 - 奇怪的行为

private void btnRun_Click(object sender, EventArgs e) 
    { 
     label1.Visible = true; 

     if (SelectDatabase()) 
     { 
      if (string.IsNullOrEmpty(txtFolderAddress.Text)) 
       MessageBox.Show("Please select a folder to begin the search."); 
      else 
      { 

       if (cbRecurse.Checked == false || Directory.GetDirectories(initialDirectory).Length == 0) 
       { 
        CheckSingleFolder(); 
       } 
       else 
       { 
        CheckSingleFolder(); 
        directoryRecurse(initialDirectory); 
       } 

           } 
     } 


    } 

实际上,它做了一些检查,然后开始寻找特定文件的一些目录递归。但是,直到目录被递归之后,才能使标签可见的第一行代码才会出现?任何人都知道为什么会这样?

谢谢。

+0

尝试刷新您的表单,如果您的功能持有它,可能会有所帮助。 'form1.refresh();' – Prix 2011-04-04 13:42:19

回答

8

你在UI线程中正在做所有事情,这是一个非常糟糕的主意 - UI无法更新,对事件做出反应直到完成。

您应该使用后台线程并使用Control.BeginInvoke或使用BackgroundWorker进度更新UI等。

基本上有在WinForms的两个黄金规则(与WPF/Silverlight的类似):

  • 不要做任何事情可以采取在UI线程的时间显著量
  • 别t触摸任何线程的任何UI元素其他比UI线程
+0

然后等待新线程完成的最佳方式是什么?我有另一种方法,必须等到递归完成。如果我使用单独的线程,然后使用while(thread.isalive){}之类的东西,它显然会阻塞该线程,直到新线程完成。你会推荐什么?谢谢。 – 2011-04-04 13:49:47

+0

@Darren:使文件处理代码回调到UI线程,调用后续需要的任何方法(例如重新启用按钮等)。 – 2011-04-04 13:51:37

+0

非常感谢。所以我简单地说,例如,使用这样的东西:btnRun.Invoke((MethodInvoker)委托{/ /运行方法}); – 2011-04-04 13:58:24

1

您的整个方法当前以阻止单元的形式运行 - 添加Application.DoEvents()作为解决方法,但实际上您应该在后台线程中执行此类处理,即使用后台工作程序。

+3

Blech。 Application.DoEvents是一个黑客 - 这个代码不应该在UI线程上执行。 – 2011-04-04 13:41:33

+0

gaah我只是在写这个 – BrokenGlass 2011-04-04 13:42:36

+0

而且非常危险的黑客。我很高兴你补充说明;你从我身上侥幸逃脱了。 ;-)有太多的答案使用错误的建议来使用Application.DoEvents。 – 2011-04-04 13:47:01

1

代码在绘制用户界面的同一个线程上执行。因此,在代码执行时,您的UI不会被重新绘制。一旦按钮点击代码完成后,用户界面将重新绘制,并且label1被无形地绘制。

您可以使用例如TaskBackgroundWorker将代码移动到单独的线程中。但是,您不能直接从不同的线程设置UI属性,因此您需要小心地从UI线程设置UI属性,或者关于如何从另一个线程更新GUI,请执行see this question

1

视图不会更新,直到代码块完成。所以我会为递归部分提出一个BackgroundWorker

1

解释:标签被设置为可见,并且它被无效(需要重绘),但是Windows消息泵在它运行空闲之前不会开始重新绘制。所以你的代码会阻止它。

一个简单的解决方案是在将其设置为可见之后立即调用label1.Update()

更好的解决方案是将耗时的代码移动到线程(Backgroundworker)。