2010-11-05 61 views
3

我想了解更多关于线程的信息,并创建了一个可以更改标签背景颜色的小测试应用程序。简单线程测试

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    //lblColor 
    public Color theLabel 
    { 
     get { return this.lblColor.BackColor; } 
     set { this.lblColor.BackColor = value; } 
    } 

    //btnStart 
    private void btnStart_Click(object sender, EventArgs e) 
    { 
     ThreadTest cColor = new ThreadTest(); 
     Thread tColor = new Thread(new ThreadStart(cColor.ChangeColor)); 

     tColor.Start(); 
    } 
} 

而且......

public class ThreadTest 
{ 
    public void ChangeColor() 
    { 
     Form1 foo = new Form1(); 
     while (true) 
     { 
      foo.theLabel = Color.Aqua; 
      foo.theLabel = Color.Black; 
      foo.theLabel = Color.DarkKhaki; 
      foo.theLabel = Color.Green; 
     } 
    } 
} 

唯一的问题是,为什么我不能让这段代码的工作?我可以看到ChangeColor中的代码运行,但标签的颜色不变。

+2

那是因为你的线程”不是个考虑的想法t异步...表单确实与您更改的代码驻留在同一个线程中,因此表单无法重绘本身。我只是懒得现在形成一个答案,这正是解释为什么以及如何使用代表。 – Bobby 2010-11-05 14:53:56

+0

正如我在下面的答案所述,代码不工作,因为Form1 foo = new Form1();在ThreadTest.ChangeColor ...使用参数化线程启动...关于backgroundworker等所有建议也是好主意。 – 2010-11-05 15:00:38

回答

5

乍一看,你正在构建一个新的形式

Form1 foo = new Form1(); 

内ThreadTest,从不显示形式,我的猜测是你打算用btnStart更改窗体上的窗体颜色?您有两个选项,可以将表单传递给ParameterizedThreadStart,也可以重新编写代码以在现有表单上运行。

此外,根据编写的代码,你可能会需要使用调用来更新表单的状态,你不能有工作线程更新UI。我会调整你的代码,并发布一个修改后的例子,如果有人不打我。

编辑

在这种情况下,你不需要调用......但这里是我认为你打算......

private void btnStart_Click(object sender, EventArgs e) 
{ 
    ThreadTest cColor = new ThreadTest(); 
    Thread tColor = new Thread(new ParameterizedThreadStart(cColor.ChangeColor)); 

    tColor.Start(this); 
} 

public class ThreadTest 
{ 
    public void ChangeColor(Object state) 
    { 
    Form1 foo = (Form1) state; 
    while (true) 
    { 
     foo.theLabel = Color.Aqua; 
     foo.theLabel = Color.Black; 
     foo.theLabel = Color.DarkKhaki; 
     foo.theLabel = Color.Green; 
    } 
    } 
} 

而且,设置是非常重要的工作线程作为后台线程,否则当您关闭表单时,线程将保持该应用程序处于打开状态。

tColor.IsBackground = true; 

附加的例子

稍微不同的例子是有多个线程试图更新相同的值,看看它们是如何交错......简单的片段来让球滚动。

private void btnStart_Click(object sender, EventArgs e) 
{ 
    CreateBackgroundColorSetter(Color.Aqua); 
    CreateBackgroundColorSetter(Color.Black); 
    CreateBackgroundColorSetter(Color.DarkKhaki); 
    CreateBackgroundColorSetter(Color.Green); 
} 


private void CreateBackgroundColorSetter(Color color) 
{ 
    var thread = new Thread(() => 
          { 
           while (true) 
           { 
           theLabel = color; 
           Thread.Sleep(100); 
           } 
          }); 
    thread.IsBackground = true; 

    thread.Start(); 
} 
+0

双重+1样本。 – cjk 2010-11-05 15:19:22

3

你有2个问题

a)您不应该更新其他线程

B中的UI),即使你被允许这样做,你需要告诉UI重新绘制

这些都是不平凡的问题

如果你只是用线程尝试再使用的Debug.WriteLine,看看有什么后台线程正在做

如果你确实需要更新在后台UI然后查找的BeginInvoke和InvokeNeeded

+0

如果您更正了ThreadTest.ChangeColor以不构建新窗体,代码实际上会运行。见下面的例子。通常情况下,您确实需要调用(我很惊讶这种情况并不需要)。 – 2010-11-05 15:06:27

1

如果你真的需要做线程的GUI应用程序,你将需要BackgroundWorker或类似的东西。如前所述,其它线程不能无论如何所以显示的示例是移动长期运行的工作项目从你的主线程的一个更好的模型更新GUI。

BackgroundWorker的类可以 到一个单独的, 专用线程运行的操作。耗时 像下载和数据库 交易可能会导致您的用户 界面(UI)看起来好像它 已停止响应,而他们是 运行。当您需要响应式UI 并且您面临与此类操作相关的长时间延迟 时,BackgroundWorker类提供了一个便利的解决方案。

+0

我同意BackgroundWorker是处理这个应用程序的一个更好的方法,并且最终会在你遇到更复杂的例子时被需要,但是代码不运行的原因是因为Form1 foo = new Form1(); ThreadTester.ChangeColor中的语句(请参阅我的答案)。 – 2010-11-05 15:23:07

+0

@Calgary编码器 - 是的,这个信息是为了补充现有的与相关原因有关的答案。 – 2010-11-05 15:24:26