简体   繁体   English

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

[英]When creating a new thread, changes to GUI are not being made (C#)

With some help I have managed to create a new thread, although the method appears to execute, the conditions of the method either make a green or red light appear, although when running the method (Check1..etc) without the new thread the changes are reflected on the GUI (eg Red / Green Light Appears), but when creating a new thread and running the method the changes are not reflected on the Form / GUI. 在一些帮助下,我设法创建了一个新线程,尽管该方法似乎可以执行,但该方法的条件使绿色或红色亮起,尽管在没有新线程的情况下运行方法(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;
        }

This is how WinForms is designed. 这就是WinForms的设计方式。 You can't make changes from another thread. 您不能从另一个线程进行更改。 the solution usually is to use asynchronous delegate. 解决方案通常是使用异步委托。

First of all add this declaration 首先添加此声明

 public delegate void MyDelegate1 ();

 public delegate void MyDelegate2 (); 

Then When you are in another thread You should do: 然后,当您处于另一个线程中时,您应该执行以下操作:

MyDelegate1 d1= new MyDelegate1 (displayGreen1);

 this.BeginInvoke(d1);

 MyDelegate2 d2= new MyDelegate2 (displayRed1);

 this.BeginInvoke(d2);

At your skill level, it would be best to: 以您的技能水平,最好是:

  • use timer in the form to check some status variable (say bool _pb1Visible and bool _pb2Visible ) 使用表单中的计时器检查某些状态变量(例如bool _pb1Visiblebool _pb2Visible
  • in the timer event update picturebox visibility 在计时器事件中更新图片框可见性
  • in the thread, update ONLY bool member variables mentioned above. 在线程中,仅更新上述的布尔成员变量。

It will work like a charm! 它将像魅力一样运作!

Simple example: 简单的例子:

In your Check1() method, instead of: 在您的Check1()方法中,而不是:

displayGreen1();

put

_pb1Visible=true;
_pb1Visible=false;

and instead of 而不是

displayRed1();

put

_pb1Visible=false;
_pb1Visible=true;

Put the timer on the form. 将计时器放在窗体上。 In the timer event, do the: 在计时器事件中,执行以下操作:

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

This is happening because UI controls can only be updated from the UI thread. 发生这种情况是因为UI控件只能从UI线程进行更新。 When you do not create a new thread, the code which updates the controls runs on the UI thread, so it works as you expect. 当您创建新线程时,更新控件的代码在UI线程上运行,因此可以按预期工作。 When you do create a new thread, because this thread is not the UI thread, the code which is supposed to update the controls fails to do so. 当您确实创建一个新线程时,因为该线程不是 UI线程,所以应该更新控件的代码无法这样做。

You can ensure that the code which updates the controls runs on the UI thread by changing the method calls to:- 您可以通过将方法调用更改为以下方式来确保更新控件的代码在UI线程上运行:

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

and

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

Incidentally (unrelated to your current problem):- 偶然地(与您当前的问题无关):-

Try to avoid creating an explicit thread. 尝试避免创建显式线程。 Instead use the thread pool to manage the thread for you, eg ThreadPool.QueueUserWorkItem(x => InitChecks()) . 而是使用线程池为您管理线程,例如ThreadPool.QueueUserWorkItem(x => InitChecks()) (Note that this will still run on a non-UI thread so you still need to use BeginInvoke() as detailed above.). (请注意,这仍将在非UI线程上运行,因此您仍然需要使用BeginInvoke() ,如上文所述。) The thread pool knows best about when to create and execute a thread and using it will, ultimately, make your code more efficient. 线程池最了解何时创建和执行线程,使用线程最终将使您的代码更高效。

Try to avoid catching all exception types in your try{...}catch{...} . 尝试避免在try{...}catch{...}捕获所有异常类型。 This is stating that your code knows what to do when any type of exception is thrown. 这说明您的代码知道抛出任何类型的异常时怎么办。 Instead, only catch exceptions which you know exactly how to handle, 相反,只捕获您确切知道如何处理的异常,

eg 例如

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

Note that it is OK to also have a catch block for all exception types as long as you rethrow the exception when exiting the block, 请注意,也可以对所有异常类型都具有catch块,只要您在退出块时重新抛出该异常,

eg 例如

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