繁体   English   中英

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

[英]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 _pb1Visiblebool _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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM