Child Form Freezes when Main form runs

I have a C# .net application that I am writing.
Currently there is a timer on the Main form that runs down from 800 seconds at the point the code gets ran.
When the main form loads It spawns a second form with a second timer at 1800 seconds. When the main form runs and finishes it updates the timer on the second form back to 1800. If the timer for the second form ever reaches 0 it sends an email.

Basically I am running a watchdog timer with the second form.

The problem I have is when the code runs on the main form everything locks up until its done.

Here is the Second form code(Watch dog)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace PGEN_v3
{
    public partial class WatchDog : Form
    {
       public static int counter = 0;
        public WatchDog()
        {
            InitializeComponent();
           

        }

        private void btn_TestWatch_Click(object sender, EventArgs e)
        {

                string strFrom = "PGEN@xxxxx";
                string strTo = "xxxx@xxxx";
                string strSubject = "xxxx";
                string strBody = "xxxx";
                Form1.sendEmail(strFrom, strTo, strSubject, strBody);
          
        }

        private void WatchDog_Load(object sender, EventArgs e)
        {                       
            this.ControlBox = false;
            counter = 1800;
            lbl_WATCHCOUNT.Text = counter.ToString();
            timer1.Interval = 1000;
            timer1.Start();

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            counter--;
            lbl_WATCHCOUNT.Text = counter.ToString();
            if (counter == 0)
            {
                string strFrom = "PGEN@xxxxx";
                string strTo = "xxxx@xxxx";
                string strSubject = "xxxx";
                string strBody = "xxxx";
                Form1.sendEmail(strFrom, strTo, strSubject, strBody);
            }
        }
    }
}

Open in new window



Here is an example of the main form code

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace PGEN_v3
{
    public partial class Form2 : Form
    {
        int counter = 0;
        public Form2()
        {
            
            InitializeComponent();
        }

        private void Form2_Load(object sender, EventArgs e)
        {

            counter = 800;
            lbl_MainCounter.Text = counter.ToString();
            timer1.Interval = 1000;
            timer1.Start();
        }

        private void Button_Scan_Click(object sender, EventArgs e)
        {
        //RUN CODE
counter = 800;
watchdogform.counter = 1800;
        }


        private void timer1_Tick(object sender, EventArgs e)
        {
            if (counter == 0)
            {
                Button_Scan_Click(sender, e);
            }
            counter--;
            lbl_MainCounter.Text = counter.ToString();


        }
    }
}

Open in new window



How can I get he second form to spawn a different thread and it not lockup the child?
It also locks up the count down timer on the main form until the code is done.
My example code might not 100% work since I just pulled out bits an pieces from the actual working code. It should give you the idea though.

Thanks
Fixitben
LVL 7
fixitbenAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Mike TomlinsonHigh School Computer Science, Computer Applications, and Mathematics TeachersCommented:
The problem I have is when the code runs on the main form everything locks up until its done.

Then that code needs to run in a different thread.

The "work" should be put into a different thread, NOT the child form.
Karrtik IyerSoftware ArchitectCommented:
If I understand your requirement, you want to trigger a mail if operation (button scan click) initiated on main form takes more than 1800 seconds(or some other unit of time).
I don't think you  dont need a child form to accomplish this task. Conceptually this is how I would go about doing this work.
1) Spawn background worker thread as soon as main form starts it work. ( https://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx)
2) An event (signal) is shared between main form and this thread, basically it is an input to this thread. This event signals completion of main thread's work. ( https://msdn.microsoft.com/en-us/library/system.threading.eventwaithandle(v=vs.110).aspx)
3) This worker thread waits for this event with timeout of 1800.
4) If wait returns timeout, then it means the main thread work is taking more than 1800 units. Hence you need to trigger a mail.
anarki_jimbelSenior DeveloperCommented:
Fundamentals of JavaScript

Learn the fundamentals of the popular programming language JavaScript so that you can explore the realm of web development.

anarki_jimbelSenior DeveloperCommented:
Yeah, Karrtik came first :)
fixitbenAuthor Commented:
Ok After looking at it some more. I might be wrong.

The counter for both forms stops. I have created a simple example of this with only one form. I don't think the issue is with the fact that I have two forms. It occurs with one form too.
When it runs the scan portion runs it stops counting down below zero. I would l think the counter would keep counting no mater what happens. This example pulls a project number then generates a path to check and see if it is valid or not. It checks around 20,000 paths.

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Configuration;
using System.Xml;
using System.Threading;


namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {   int counter = 0;
        public Form1()
        {
            InitializeComponent();
        }



        private void Form1_Load(object sender, EventArgs e)
        {   
            counter = 6;
           label2.Text = counter.ToString();
            timer1.Interval = 1000;
            timer1.Start();

        }

        private void Scan()
        {
            DataTable table = GetProjects();
            foreach (DataRow row in table.Rows)
            {

                String PN = row["ProjectNumber"].ToString();
                string PATH = GetPath100(PN, "R:\\");
                bool PATHCHECK = !Directory.Exists(PATH);
                while ( PATHCHECK)
                { 
                    label1.Text = PATH.ToString();
                    listBox1.Items.Add(PATH); 
                }
            }

        }


        public static DataTable GetProjects()
        {
            DataTable dataTable = new DataTable();


                SqlConnection conn = new SqlConnection("Data Source=server;Initial Catalog=db;User ID=user;Password=passwd");
                string query = "Select ProjectNumber, ProjectManager, Date  FROM [ProjMgt].[dbo].[tblProjectInfo]  where  ISNUMERIC(projectnumber) = 1 and len(ProjectNumber) >= 6 order by CAST(ProjectNumber AS int)";
                SqlCommand cmd = new SqlCommand(query, conn);
                conn.Open();
                SqlDataAdapter dt = new SqlDataAdapter(cmd);


                dt.Fill(dataTable);
                return dataTable;

        }

        public string GetPath100(String PN, String STORAGEPATH)
        {
            int TENS = (Int32.Parse(PN) / 10) * 10;
            int HUNDREDS = (Int32.Parse(PN) / 100) * 100;
            int THOUSANDS = (Int32.Parse(PN) / 1000) * 1000;
            //PATH = TENS.ToString;
            String PATH = STORAGEPATH + "" + HUNDREDS + " JOBS\\" + TENS + " JOBS\\" + PN;
            //Console.WriteLine("R:\\" + HUNDREDS + " JOBS\\" + TENS + " JOBS\\" + PN);
            return PATH;

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (counter == 0)
            {
                Scan();
            }
            counter--;
            label2.Text = counter.ToString();


        }
        }


    }

Open in new window

Mike TomlinsonHigh School Computer Science, Computer Applications, and Mathematics TeachersCommented:
Right...as I said, the "work" needs to be done in a different thread:
            if (counter == 0)
            {
                Scan(); // <-- this needs to be in a different thread
            }

Open in new window


Also, how are you expecting this loop to ever exit?!
                bool PATHCHECK = !Directory.Exists(PATH);
                while ( PATHCHECK)
                { 
                    label1.Text = PATH.ToString();
                    listBox1.Items.Add(PATH); 
                }

Open in new window

fixitbenAuthor Commented:
The loop will end when the path is corrected on the file server. This code it to monitor for accidental folder deletions. All paths should exist. If they don't it means it was moved or deleted and needs to be corrected. I will try wrapping the scan() in a thread and see how it works.

Thanks for your help so far.
Mike TomlinsonHigh School Computer Science, Computer Applications, and Mathematics TeachersCommented:
No...that loop will run forever, as the existence of the directory is checked for OUTSIDE of the while loop.  It might not be causing a problem now, but if the directory ever doesn't exist, then you will.
fixitbenAuthor Commented:
HI Mike,

There is  a bunch of code in the scan() that updates the UI (progressbar, paths processed) I am getting an error about cross-thread operations. Is there an easy way to pass information back to the ui from the second thread?

Additional information: Cross-thread operation not valid: Control 'listBox1' accessed from a thread other than the thread it was created on.

In my actual code I have this for the while loop. Which will check the path each time. Sorry I left that out in the example.
while (ARCHIVEPATHCHECK && PATHCHECK)
                            {
                                                    listBox1.Items.Add(PATH);
                                                                PATHCHECK = !Directory.Exists(PATH);

                            }

Open in new window

Mike TomlinsonHigh School Computer Science, Computer Applications, and Mathematics TeachersCommented:
There are lots of ways to do it.  Which Version C# are you using?...
fixitbenAuthor Commented:
Visual studio 2013
Mike TomlinsonHigh School Computer Science, Computer Applications, and Mathematics TeachersCommented:
Okay.  Whenever you need to update the GUI, use code like this:
this.Invoke((MethodInvoker)delegate {
    listBox1.Items.Add(PATH);
});

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
fixitbenAuthor Commented:
That worked perfect. I was looking at it the opposite way. I had tried the thread thing, but was putting it on the opening of the second form.
Now it makes a lot more sense. This is my first time dealing with threads.
fixitbenAuthor Commented:
One more question. Is there an easy way to kill the thread? I have a cancel button, but want the thread to die when I hit cancel.
Mike TomlinsonHigh School Computer Science, Computer Applications, and Mathematics TeachersCommented:
Create a Form level Boolean that you toggle when the Thread should be cancelled.  From within the thread, especially inside tight loops, check that flag and exit appropriately.
fixitbenAuthor Commented:
Thanks. I figured it out. I did exactly what you said.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.