当创build一个新线程时,对GUI的更改没有被制作(C#)

有一些帮助,我设法创build一个新的线程,虽然方法似乎执行,方法的条件或者使绿色或红色的灯光出现,虽然当运行方法(Check1..etc)没有新线程的变化被反映在GUI上(例如Red / Green Light出现),但是当创build一个新线程并运行该方法时,这些改变不会反映在Form / GUI上。

// Method / Action to start the checks private void StartChecks_Click(object sender, EventArgs e) { Thread t = new Thread( o => { InitChecks(); }); t.Start(); } // Check1 public void Check1() { // lets grabs the info from the config! var lines = File.ReadAllLines("probe_settings.ini"); var dictionary = lines.Zip(lines.Skip(1), (a, b) => new { Key = a, Value = b }) .Where(l => l.Key.StartsWith("#")) .ToDictionary(l => l.Key, l => l.Value); // lets set the appropriate value for this check field label1.Text = dictionary["#CheckName1"]; // lets define variables and convert the string in the dictionary to int for the sock.connection method! int portno1; int.TryParse(dictionary["#PortNo1"], out portno1); // Convert hostname to IP, performance issue when using an invalid port on a hostname using the TcpClient class! IPAddress[] addresslist = Dns.GetHostAddresses(hostname2); foreach (IPAddress theaddress in addresslist) { // Attempt to create socket and connect to specified port on host TcpClient tcP = new System.Net.Sockets.TcpClient(); try { tcP.ReceiveTimeout = 1; tcP.SendTimeout = 1; tcP.Connect(theaddress, portno1); displayGreen1(); tcP.Close(); } catch { displayRed1(); } } } // Change the lights when the condition is met public void displayGreen1() { pictureBox2.Visible = false; pictureBox1.Visible = true; } private void displayRed1() { pictureBox2.Visible = true; pictureBox1.Visible = false; } 

Solutions Collecting From Web of "当创build一个新线程时,对GUI的更改没有被制作(C#)"

这是因为UI控件只能从UI线程更新。 当你创建一个新线程时,更新控件的代码在UI线程上运行,所以它可以像你期望的那样工作。 当你创建一个新的线程,因为这个线程不是 UI线程,应该更新控件的代码不能这样做。

您可以通过更改方法调用来确保更新控件的代码在UI线程上运行: –

 this.BeginInvoke(new Action(() => displayRed1())); 

 this.BeginInvoke(new Action(() => displayGreen1())); 

顺便说一句(与您目前的问题无关): –

尽量避免创建一个明确的线程。 而是使用线程池为您管理线程,例如ThreadPool.QueueUserWorkItem(x => InitChecks()) 。 (请注意,这仍然会在非UI线程上运行,因此您仍然需要使用BeginInvoke() ,如上所述)。 线程池知道什么时候创建和执行一个线程,使用它最终会使你的代码更有效率。

尽量避免捕获try{...}catch{...} 所有异常类型。 这就是说,当任何类型的异常被抛出时,你的代码知道该怎么做。 相反,只有捕获你确切知道如何处理的异常,

例如

 try { ... } catch(TcpException) { ... } catch(AnotherKnownException) { ... } ... 

请注意,只要在退出块时重新抛出异常,也可以为所有异常类型设置catch块,

例如

 try { ... } catch(KnownException) { ... } catch(Exception) { // perform some logging, rollback, etc. throw; } 

这就是WinForms的设计。 您不能从另一个线程进行更改。 解决方案通常是使用异步委托。

首先添加这个声明

  public delegate void MyDelegate1 (); public delegate void MyDelegate2 (); 

那么当你在另一个线程中你应该这样做:

 MyDelegate1 d1= new MyDelegate1 (displayGreen1); this.BeginInvoke(d1); MyDelegate2 d2= new MyDelegate2 (displayRed1); this.BeginInvoke(d2); 

在你的技能水平上,最好是:

  • 使用计时器的形式来检查一些状态变量(比如bool _pb1Visiblebool _pb2Visible
  • 在计时器事件更新picturebox知名度
  • 在线程中,只更新上面提到的bool成员变量。

它会像魅力一样工作!

简单的例子:

在您的Check1()方法中,而不是:

 displayGreen1(); 

 _pb1Visible=true; _pb1Visible=false; 

而不是

 displayRed1(); 

 _pb1Visible=false; _pb1Visible=true; 

把计时器放在窗体上。 在计时器事件中,执行以下操作:

 pictureBox2.Visible = _pb2Visible; pictureBox1.Visible = _pb1Visible;