[英]When creating a new thread, changes to GUI are not being made (C#)
在一些帮助下,我设法创建了一个新线程,尽管该方法似乎可以执行,但该方法的条件使绿色或红色亮起,尽管在没有新线程的情况下运行方法(Check1..etc)时,更改会在GUI上反映出来(例如,出现红/绿灯),但是在创建新线程并运行方法时,更改不会反映在窗体/ 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;
}
这就是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 _pb1Visible
和bool _pb2Visible
) 它将像魅力一样运作!
简单的例子:
在您的Check1()
方法中,而不是:
displayGreen1();
放
_pb1Visible=true;
_pb1Visible=false;
而不是
displayRed1();
放
_pb1Visible=false;
_pb1Visible=true;
将计时器放在窗体上。 在计时器事件中,执行以下操作:
pictureBox2.Visible = _pb2Visible;
pictureBox1.Visible = _pb1Visible;
发生这种情况是因为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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.