创建新线程时,不会对GUI进行更改(C#)

时间:2011-12-17 11:55:39

标签: c# .net windows

通过一些帮助,我设法创建了一个新线程,虽然该方法似乎执行,但该方法的条件要么出现绿灯或红灯,尽管在运行方法(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;
        }

3 个答案:

答案 0 :(得分:3)

这就是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);

答案 1 :(得分:2)

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

  • 在表单中使用计时器来检查某个状态变量(例如bool _pb1Visiblebool _pb2Visible
  • 在计时器事件更新图片框可见性
  • 在线程中,更新上面提到的bool成员变量。

它会像魅力一样发挥作用!

简单示例:

Check1()方法中,而不是:

displayGreen1();

_pb1Visible=true;
_pb1Visible=false;

而不是

displayRed1();

_pb1Visible=false;
_pb1Visible=true;

将计时器放在表单上。在计时器事件中,执行:

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

答案 2 :(得分:2)

这种情况正在发生,因为UI控件只能从UI线程更新。当创建新线程时,更新控件的代码将在UI线程上运行,因此它可以按预期工作。当你创建一个新线程时,因为这个线程不是 UI线程,所以应该更新控件的代码不能这样做。

通过将方法调用更改为: -

,可以确保更新控件的代码在UI线程上运行
this.BeginInvoke(new Action(() => displayRed1()));

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

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

尽量避免创建显式线程。而是使用线程池为您管理线程,例如ThreadPool.QueueUserWorkItem(x => InitChecks())。 (请注意,这仍将在非UI线程上运行,因此您仍需要使用BeginInvoke(),如上所述。)。线程池最了解何时创建和执行线程并最终使用它将使代码更有效。

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

e.g。

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

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

e.g。

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