Link to home
Start Free TrialLog in
Avatar of Gsmith0159
Gsmith0159

asked on

Need assistance updating a UI from its original thread after a timer expiry action.

Calling all experts,

While I am relatively new to C# and .Net I like to believe I done my diligence researching my problem.  However it must be something I am missing.  I'm trying to update a Dundas chart however I keep getting an error telling me that I must do the update from the original thread.  I'm going to various sections of the Visual Studio documentation andthe most promising link was http://msdn.microsoft.com/en-us/library/ms171728.aspx as it had many examples.  I've gone to various other links and sub links but have not been able to make the call to the original thread that created the UI work.  I've attached a number of files showing my set up and the actual error. The file "Shows cross thread error 1230090912.png" is a screenshot of the actual error at runtime. The file "Section from rotuine called after timer event showing BG setup 1230090911.png" is a section of the routine that is called after the timer expires. Next we have "Statement showing BG worker private definition 1203090908.png" which is the background worker private definition. Along with "Statement showing BG worker definition 1203090907.png" this is the worker definition for the background task.  Followed by"Routine that resets chart view 1230090906.png" which is the actual routine that resets the Dundas chart.

Please let me know if you need any other further information..............

I appreciate all your help and consideration...............

Signed,
Desperate in Boston :)

Routine-that-resets-chart-view-1.png
Section-from-rotuine-called-afte.png
Shows-cross-thread-error-1230090.png
Statement-showing-BG-worker-defi.png
Statement-showing-BG-worker-priv.png
Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

Any chance you can post that code into a code text block, or as a .cs?  The snapshots are a little difficult to follow outside of the context of their complete classes, and impossible to edit. ;)

Here's an example of setting a property on a TextBox control, borrowing from the example you cited in your question.

Make any sense?
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 WindowsFormsApplication1
{
	public partial class Form1 : Form
	{
		delegate void SetTextBoxTextDelegate(string NewText);

		public void SetTextBoxText(string NewText)
		{
			if (this.textBox1.InvokeRequired)
				this.Invoke(new SetTextBoxTextDelegate(SetTextBoxText), new object[] { NewText });
			else
				this.textBox1.Text = NewText;
		}

		public Form1()
		{
			InitializeComponent();
			new Form2(this).Show();
		}

		private void Form1_Load(object sender, EventArgs e)
		{

		}
	}
}

Open in new window

That is a form with a text box control. If you open another form, for example, and try Form1.textBox1.Text = "hello world" you get the cross-threading error you have above.  So instead, one would call Form1.SetTextBoxText("Hello World") (a method I added to the form).

That function checks textBox1.InvokeRequired, which returns true if the calling thread is different than the thread the textBox was created on.  If it returns true (i.e. threads are different) then the forms Invoke method is called in order to execute the function pointed to by the SetTextBoxTextDelegate (which is itself, creating a kind of finite logic loop) on the same thread that the textBox was created on. If it returns false, then the calling thread is the thread the text box was created on, so it just directly sets textBox.text.
Avatar of Gsmith0159
Gsmith0159

ASKER

tgerbert, Thank you very much for your quick response.  I tried using the SetTextBoxText example as in the link that I posted in the question.  However I got an error stating that the UI must be updated on the same thread in which it was created.  This forced me to abandon that approach.  At the for the researching, again mostly around the link in the question, I use the asynchronous approach as suggested and came up with the are.  I did look at InvokeRequired and in every case it was always true.  I'm confident that despite the check that I am not making for InvokeRequired is always true.  The greater question may be how do you update the UI from its original thread when you are on an alternate thread?

Thanks once again....................

The Invoke method will do that.  The Invoke method will execute a method on the same thread that the control was created on.  i.e. If you call Form1.Invoke, the code will execute on the same thread that Form1 was created on.

Here's another simple example using a BackgroundWorker (one form with a text box and a button).

I might be able to offer some more insight if you can post your code, it's hard for me to say what's actually going on based on the screen shots.
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 WindowsFormsApplication1
{
	public partial class Form1 : Form
	{
		BackgroundWorker worker;

		delegate void SetTextDelegate(string Text);

		public Form1()
		{
			InitializeComponent();
		}

		void SetText(string Text)
		{
			// When called by the background worker, InvokeRequired will be true
			if (this.textBox1.InvokeRequired)
			{
				// "d" is now a variable, but instead of a variable that
				// points to/contains an object or string or something,
				// it points to a function - the function it points to
				// is SetText, which is *this* function
				SetTextDelegate d = new SetTextDelegate(SetText);

				// This line calls this forms .Invoke method, which will
				// execute the function pointed to by "d" (which is *this* function)
				// on the same thread the form and text box were created on
				// The "first" time through this function, when called by
				// background thread, we're just going to use this .Invoke
				// method to re-run this same method, but on the form's thread
				this.Invoke(d, new object[] { Text });
			}
			else
			{
				// The "second" time through this function will be the result
				// of the .Invoke, which means we'll be on the same thread as 
				// the form, so the textBox1.InvokeRequired above will return
				// false, and since we're on the same thread as the form and
				// text box we can directly set the .Text property.
				this.textBox1.Text = Text;
			}
		}

		void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			// RunWorkerCompleted runs on same thread the
			// background worker was created on, which
			// is this form, so can set .Text directly
			textBox1.Text = "Worker Completed";
		}

		void worker_DoWork(object sender, DoWorkEventArgs e)
		{
			// DoWork event runs on background thread
			// so this delegate/invoke work around is necessary
			SetText("Worker Started");
			System.Threading.Thread.Sleep(5000);
		}

		private void button1_Click(object sender, EventArgs e)
		{
			worker = new BackgroundWorker();
			worker.DoWork += new DoWorkEventHandler(worker_DoWork);
			worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
			worker.RunWorkerAsync();
		}


	}
}

Open in new window

tgerbert,

Thank you for your clear explanation.  I tried incorporating it into the code that I have developed however I got a collection modified error(attached as "Code Collection Modified Error 1230091257.png".  I was wondering if you had any thoughts as to why the code was giving me this error?  I've attached my code was one particular below.

I set up a timer that will expire every 30 seconds.  When the timer expires it calls the routine "PMD_Ping_Entire_Dataset_Update".  I've taken the code that you provided as a result of a button click and placed it in the start of the "PMD_Ping_Entire_Dataset_Update" routine.

The rest of your code sections are at the end of the code listing.

Please try not to laugh too hard when reviewing my code.  Remember I am a beginner but I consider myself to be passionate and what I'm doing.

Thanks,
George
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;

using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Xml;
using System.Management;
using System.Collections;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using System.Timers;



namespace Phoenix_Main_Display
{
    public partial class Phoenix_Main_Display : Form
                
    {
        //Init the counter varaibles for the Time_Ping Snap Shot routine
        public static string[] PMD_TP_Device_to_Scan_For = new string[100000];
        public static int PMD_TP_Phoenix_Records_In_Inventory_DB = 0;

        //Init the counter varaibles for the Time_Ping Timed Update routine
        public static string[] PMD_TUODPR_Device_to_Scan_For = new string[100000];
        public static int PMD_TUODPR_Phoenix_Records_In_Inventory_DB = 0;


        //Init the counter varaibles for the storing the user selected
        //device that will have it's response information displayed
        public static string[] PMD_TP_Device_Response_Time = new string[100000];
        public static int PMD_TP_Phoenix_Number_Of_Response_Time_Records = 0;

        //Init the counter varaibles for the storing the user selected
        //device that will have it's response information displayed timed update
        public static string[] PMD_TUODPR_Device_Response_Time = new string[100000];
        public static int PMD_TUODPR_Phoenix_Number_Of_Response_Time_Records = 0;


        //Temp holding variable so that we can process a record at a time
        //to see if it matches the one the user selected
        public static string PMD_TP_Device_Ping_Response_Data_Temp_Holding = "";

        //Temp holding variable so that we can process a record at a time
        //to see if it matches the one the user selected Timed Update
        public static string PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding = "";

        //Init the variables the will read in the response times from the 
        //ping scanner database
        public static string[] PMD_TP_Device_Ping_Response_Data = new string[100000];
        public static int PMD_TP_Phoenix_Records_In_PingScan_DB = 0;

        //Init the variables the will read in the response times from the 
        //ping scanner database TIMED UPDATE
        public static string[] PMD_TUODPR_Device_Ping_Response_Data = new string[100000];
        public static int PMD_TUODPR_Phoenix_Records_In_PingScan_DB = 0;

        //Set a global for the number of items in treeview
        //inventory list
        public static int PMD_Inventory_List_Node_Count = 0;

        //Define the indicator for the variable that lets us know 
        //if the program found a prevously defined classification
        public int PMD_Classification_Exist = 0;

        //Init the IP address to ping variable in the Timed_Ping routine
        public static string PMD_TP_IP_Address_To_Store;

        //Init the IP address to ping variable in the Timed_Ping routine TIMED UPDATE
        public static string PMD_TUOPDR_IP_Address_To_Store;
        
        //Init the classification to store
        public static string PMD_TP_Classification_To_Store;

        //Init the classification to store TIMED UPDATE
        public static string PMD_TUOPDR_Classification_To_Store;


        //Global variable to use to construct the write to 
        //the PingScan Database after ping is done
        public static string PMD_TS_Append_PingScan_Result_To_File;

        //Define the ping interval timer
        //This can be overridden by right mouse button click on the 
        //Icon the systems tray.  This is set to a one minute ping interval
        public static int PMD_TS_Ping_Interval_Timer = 60000;

        //Used to store the test array entry for the swapping of the 
        //IP address in the node list
        public static string[] PMD_TP_IP_Address_To_Store_s1 = new string[10000];
        public static string[] PMD_TP_IP_Address_To_Store_s2 = new string[10000];

        //Used to store the test array entry for the swapping of the 
        //IP address in the node list TIMED PING
        public static string[] PMD_TUODPR_IP_Address_To_Store_s1 = new string[10000];
        public static string[] PMD_TUODPR_IP_Address_To_Store_s2 = new string[10000];


        //Setup a variable to record the selected node in the tree
        public static string PMD_TP_Single_Selected_Node = "";

        //Setup a variable to record the selected node in the tree TIMED Ping
        public static string PMD_TUODPR_Single_Selected_Node = "";

        //This is the timer that tics off to perform various functions
        //such as update the ping scanner display and others
        public static int PMD_Ping_Update_Timer_Interval = 0;

        //Set the up the variable that defines the timer
        //that we will use for the Ping Update timer.
        private static System.Timers.Timer PMD_Ping_Display_Update_Timer;

        //Global variable to display the Ping Interval timer
        public static int PMD_Ping_Expire_Time_Global = 0;

        //This sets up the thread to be used for the back graound task
        //to run asynchronously
        private BackgroundWorker Background_Chart_Update_Init_View;

        //Set the worker class for the timed update
        BackgroundWorker worker;

        delegate void SetTextDelegate(string Text);
                     
                
        public Phoenix_Main_Display()
        {
            InitializeComponent();

            //Enable selection and zooming of the chart
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].CursorX.UserEnabled = true;
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].CursorX.UserSelection = true;
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisX.View.Zoomable = true;
            //Enable selection and zooming of the chart
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].CursorY.UserEnabled = true;
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].CursorY.UserSelection = true;
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisY.View.Zoomable = true;
            //Enable selection and zooming of the chart
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisX.ScrollBar.PositionInside = true;
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisY.ScrollBar.PositionInside = true;

            //Init the background worker
            this.Background_Chart_Update_Init_View = new BackgroundWorker();





            //Call the routine and initialized and load the information in the database to the 
            //display.
            PMD_Refresh_Inventory_Display();
        
        }

        private void PMS_Device_Inventory_AfterSelect(object sender, TreeViewEventArgs e)
        {

        }

        private void Phoenix_Main_Display_Load(object sender, EventArgs e)
        {
            //When the form loads goto the data base and
            //Place the inventory into the correct bucket

        }

        private void PMD_Refresh_Inventory_Display()
        {
            //This will build/rebuild the inventory display list
            //
            //*******************************************************************
            //First check to see if the inventory data file exist
            //We need a flag value to indicate if the file exist
            //or is there is a problem openning it when we try to test 
            //for the main data file in the Phoenix utility.  If the file does
            //not exist it is created.  Either way we must check for problems.
            //this is a boolean value by making the default value "false"
            try
            {
                //Open the file top see if error is generated
                using (FileStream PMD_TP_fs = new FileStream
                    ("\\Phoenix\\Inventory\\Phoenix_Inventory.txt", FileMode.OpenOrCreate))
                {
                    //Guess what.....The file has been either openned 
                    //or created successfully.  Now make sure that it is closed
                    PMD_TP_fs.Close();
                }

            }
            catch (IOException IFO_ex)
            {
                //If we can not access or create the file 
                //and we get an error.  Display the error and
                //halt the program.
                String PMD_TP_File_Exist_Message = IFO_ex.Message.ToString();
                MessageBox.Show("PMD_TP5 - " +
                    PMD_TP_File_Exist_Message + " It is being created");

                //Try creating the inventory file in case it does not exist
                try
                {
                    //Create the file with the path
                    File.CreateText("\\Phoenix\\Inventory\\Phoenix_Inventory.txt");

                }
                catch (IOException IFO_ex1)
                {
                    //If we can not access or create the file 
                    //and we get an error.  Display the error and
                    //halt the program.
                    String PMD_TP_File_Exist_Message1 = IFO_ex1.Message.ToString();
                    MessageBox.Show("PMD_TP6 - Error creating main inventory data file.  Error - " +
                    PMD_TP_File_Exist_Message1);
                }


                //Exit Phoenix.  We should put in error handling code for the 
                //exception.  First we will need to figure out what Exceptions
                //are needed.
                Application.Exit();
            }

            //This is the section where we load each record, classify
            //and display it.

            //===================================================================================
            //===================================================================================
            //First get the number of records in the data file

            //Open the datafile for a read of all of the existing data
            //so that we can compare what is discovered with what is already
            //in the datafile.

            try
            {



                using (System.IO.StreamReader PMD_TP_Open_Phoenix_Inventory_File =
                        File.OpenText("\\Phoenix\\Inventory\\Phoenix_Inventory.txt"))
                {

                    //set up a variable to read records from 
                    //the Phoenix inventory data file.  I picked a
                    //a number of 10000 as the maximum number of records
                    //that is certainy past the limmit of a small network
                    //string[] PMD_TP_Record_to_Compare = new string[10000];


                    //This section inits the varaible that holds the records
                    //an makes the entire array null
                    for (int PMD_TP_Init_Record_Counter = 0; PMD_TP_Init_Record_Counter < 10000; PMD_TP_Init_Record_Counter++)
                    {
                        //init the slot in the array
                        PMD_TP_Device_to_Scan_For[PMD_TP_Init_Record_Counter] = "";
                    }


                    //Init the counter of the records
                    PMD_TP_Phoenix_Records_In_Inventory_DB = 0;

                    //Start reading the data from the file
                    while ((PMD_TP_Device_to_Scan_For[PMD_TP_Phoenix_Records_In_Inventory_DB] =
                        PMD_TP_Open_Phoenix_Inventory_File.ReadLine()) != null)
                    {
                        PMD_TP_Phoenix_Records_In_Inventory_DB = PMD_TP_Phoenix_Records_In_Inventory_DB + 1;
                        if (PMD_TP_Phoenix_Records_In_Inventory_DB >= 9999)
                        {
                            MessageBox.Show("PMD_TP1 - Maximum number of 10000 records reached");
                        }
                    }
                }
            }
            catch (IOException IFO_ex)
            {
                //If we can not access or create the file 
                //and we get an error.  Display the error and
                //halt the program.
                String PMD_TP_File_Exist_Message = IFO_ex.Message.ToString();
                MessageBox.Show("PMD_TS2 - Error openning main inventory data file.  Error - " +
                PMD_TP_File_Exist_Message);


                //Exit Phoenix.  We should put in error handling code for the 
                //exception.  First we will need to figure out what Exceptions
                //are needed.
                Application.Exit();
            }

            //Test message to show the number of records read
            //MessageBox.Show("PMD_TP3 - Number of records read is " + PMD_TP_Phoenix_Records_In_Inventory_DB);

            //If there are not any records in the inventory file no
            //sense to process any thing else so exit out of utility
            if (PMD_TP_Phoenix_Records_In_Inventory_DB == 0)
            {

                MessageBox.Show("PMD_TP14 - Warning - There are no records in the main inventory file to display");

                //exit our of routine
                return;
            }




            //********************************************************************************************************
            //This section will pull the IP address from the Data Base and
            //place it in a variable that is used for the pings.

            //This section will setup for the database interagation.
            for (int PMD_TP_Devices_Toi_Ping_Counter = 0;
                PMD_TP_Devices_Toi_Ping_Counter < PMD_TP_Phoenix_Records_In_Inventory_DB;
                PMD_TP_Devices_Toi_Ping_Counter++)
            {
                //Cycle through to the four "," because that is where we start
                //the IP address.  When we find the IP address cycle through 
                //each character of the address so that we can store the 
                //address in to a variable that is used for the ping

                //first init the counter that keeps track if we have
                //gotten to the fourth ","
                int PMD_TP_comma_counter = 0;

                //use a for to do the actual cycling
                for (int PMD_TP_Init_Character_Counter = 0; PMD_TP_Init_Character_Counter < 50;
                    PMD_TP_Init_Character_Counter++)
                {
                    //set this in a try because if the database got corrupt 
                    //then we must flag that we could not read the record.
                    try
                    {
                        if (PMD_TP_Device_to_Scan_For[PMD_TP_Devices_Toi_Ping_Counter].
                            Substring(PMD_TP_Init_Character_Counter, 1) == ",")
                        {
                            //increment the counter that says we have found a comma
                            PMD_TP_comma_counter = PMD_TP_comma_counter + 1;

                            //if the counter = 4 then we have gotten
                            //to the postition where the IP address begins
                            if (PMD_TP_comma_counter == 4)
                            {
                                //Init the variable that contains the IP address to ping
                                PMD_TP_IP_Address_To_Store = "";

                                //store the address in a global variable for 
                                //access by the Timed_Ping utility
                                for (int IP_Address_Character_count = 1; IP_Address_Character_count < 20; IP_Address_Character_count++)
                                {
                                    //first test if this is the fifth comma indicating
                                    //that we have stored all of the ip address to ping
                                    if (PMD_TP_Device_to_Scan_For[PMD_TP_Devices_Toi_Ping_Counter].
                                        Substring(PMD_TP_Init_Character_Counter + IP_Address_Character_count, 1) != ",")
                                    {
                                        //Store the IP address in the global variable
                                        PMD_TP_IP_Address_To_Store =
                                        PMD_TP_IP_Address_To_Store +
                                        PMD_TP_Device_to_Scan_For[PMD_TP_Devices_Toi_Ping_Counter].
                                        Substring(PMD_TP_Init_Character_Counter + (IP_Address_Character_count), 1);

                                        //Set another if testing the string. If we hit an
                                        //IP_Address_Character_count of 20 at this point we have a corrupt record
                                        //in the database.
                                        //point that out in a message pop up for now but 
                                        //later convert it to a log file message
                                        if (IP_Address_Character_count >= 20)
                                        {
                                            MessageBox.Show("PMD_TS9 - Possible corrupt record in the Ping Scanner database. "
                                                + "IP address read in record is " + PMD_TP_IP_Address_To_Store);
                                        }

                                    }
                                    else
                                    {
                                        //Set the for statement up so that the we 
                                        //flag that we have reached the fifth comma
                                        //indicating the end of the IP address
                                        IP_Address_Character_count = 20;
                                    }

                                }

                                //Init the comma counting variable to set up for next IP address to read
                                PMD_TP_comma_counter = 0;


                            }
                        }
                    }
                    //Flag that we ran out characters in the string for some reason
                    catch (ArgumentOutOfRangeException PMD_TS_exception)
                    {
                        //Show that we ran out of characters to read.
                        //this is bad as we should have full records
                        //in the Ping Scanner data base.
                        //If we do not tell the user in a message
                        //but convert it to a logfile entry later
                        MessageBox.Show("PMD_TS10 - Possible corrupt record in the Ping Scanner database. "
                                                + "The error is " + PMD_TS_exception
                                                + "Data Base Record is number " + PMD_TP_Devices_Toi_Ping_Counter + " "
                                                + "and contains "
                                                + PMD_TP_Device_to_Scan_For[PMD_TP_Devices_Toi_Ping_Counter]);
                    }

                }
                //********************************************************************************************************
                //========================================================================================================


                //Diagnostic message only
                //MessageBox.Show("PMD_TS12 - IP address is " + PMD_TP_IP_Address_To_Store);

                //#################################################################################################
                //#################################################################################################
                //********************************************************************************************************
                //This section will pull the classification from the Data Base and
                //place it in a variable that is used for the pings.

                ////This section will setup for the database interagation.
                //for (int PMD_TP_Devices_Toi_Classification_Counter = 0;
                //PMD_TP_Devices_Toi_Classification_Counter < PMD_TP_Phoenix_Records_In_Inventory_DB;
                //PMD_TP_Devices_Toi_Classification_Counter++)
                //{
                //Cycle through to the six "," because that is where we start
                //the classifications.  When we find the classification cycle through 
                //each character of the classifiaction so that we can store the 
                //classification in to a variable that is used for determine
                //where in the display we place the IP address


                //first init the counter that keeps track if we have
                //gotten to the sixth ","
                PMD_TP_comma_counter = 0;

                //use a for to do the actual cycling
                //the comma we are looking for should be no more than
                //85 characters in.

                //****Note is it seems like you are getting "POSSIBLE DATABASE CORRUPT MESSAGES"
                //then you may want to check to see if one of the records is realy short and exceeding 
                //the character counter as defined in the for statment below.  It may
                //be that one of the records is shorter than 90 characters.
                //Also the same goes for devices that seem to appear to have no
                //classification but really do in the data base.  The string may be
                //to long to find the comma.
                for (int PMD_TP_Init_Character_Counter = 0; PMD_TP_Init_Character_Counter < 90;
                    PMD_TP_Init_Character_Counter++)
                {
                    //set this in a try because if the database got corrupt 
                    //then we must flag that we could not read the record.
                    try
                    {
                        if (PMD_TP_Device_to_Scan_For[PMD_TP_Devices_Toi_Ping_Counter].
                            Substring(PMD_TP_Init_Character_Counter, 1) == ",")
                        {
                            //increment the counter that says we have found a comma
                            PMD_TP_comma_counter = PMD_TP_comma_counter + 1;

                            //if the counter = 6 then we have gotten
                            //to the postition where the classification begins
                            if (PMD_TP_comma_counter == 6)
                            {
                                //Init the variable that contains the Classifiation
                                PMD_TP_Classification_To_Store = "";

                                //store the address in a global variable for 
                                //access by the Timed_Ping utility
                                for (int Classification_Character_count = 1; Classification_Character_count < 30; Classification_Character_count++)
                                {
                                    //first test if this is the seventh comma indicating
                                    //that we have stored all of the classification information
                                    if (PMD_TP_Device_to_Scan_For[PMD_TP_Devices_Toi_Ping_Counter].
                                        Substring(PMD_TP_Init_Character_Counter + Classification_Character_count, 1) != ",")
                                    {
                                        //Store the IP address in the global variable
                                        PMD_TP_Classification_To_Store =
                                        PMD_TP_Classification_To_Store +
                                        PMD_TP_Device_to_Scan_For[PMD_TP_Devices_Toi_Ping_Counter].
                                        Substring(PMD_TP_Init_Character_Counter + (Classification_Character_count), 1);

                                        //Set another if testing the string. If we hit an
                                        //Classification_Character_count of 30 at this point we have a corrupt record
                                        //in the database.
                                        //point that out in a message pop up for now but 
                                        //later convert it to a log file message
                                        if (Classification_Character_count >= 30)
                                        {
                                            MessageBox.Show("PMD_TS11 - Possible corrupt record in the Ping Scanner database. "
                                                + "IP address read in record is " + PMD_TP_Classification_To_Store);
                                        }

                                    }
                                    else
                                    {
                                        //Set the for statement up so that the we 
                                        //flag that we have reached the fifth comma
                                        //indicating the end of the IP address
                                        Classification_Character_count = 30;
                                    }

                                }

                                //Init the comma counting variable to set up for next IP address to read
                                PMD_TP_comma_counter = 0;


                            }
                        }
                    }
                    //Flag that we ran out characters in the string for some reason
                    catch (ArgumentOutOfRangeException PMD_TS_exception)
                    {
                        //Show that we ran out of characters to read.
                        //this is bad as we should have full records
                        //in the Ping Scanner data base.
                        //If we do not tell the user in a message
                        //but convert it to a logfile entry later
                        MessageBox.Show("PMD_TS8 - Possible corrupt record in the Ping Scanner database. "
                                                + "The error is " + PMD_TS_exception
                                                + "Data Base Record is number " + PMD_TP_Devices_Toi_Ping_Counter
                                                + " and contains "
                                                + PMD_TP_Device_to_Scan_For[PMD_TP_Devices_Toi_Ping_Counter]);
                    }

                }


                //Diagnostic message only
                //MessageBox.Show("PMD_TS13 - Classifiaction is " + PMD_TP_Classification_To_Store);

                //This section will check to see if there are any items in the 
                //tree.  If there are then look for the name.  If there are not any 
                //Items in the tree then skip this section.
                //Get the value of the number of items in the treeview
                PMD_Inventory_List_Node_Count =
                    PMD_Inventory_List.Nodes.Count;


                if (PMD_Inventory_List_Node_Count > 0)
                {

                    //This section will take each IP and classification and put it in 
                    //the correct catagory. If the catagory does not exist it will be 
                    //created.//Step 1 make sure catagory exist in the list.  If it does not
                    //then create the catagory

                    try
                    {
                        //This is the actual code that looks for an existing entry
                        //in the tree
                        for (int PMD_i_tree = 0; PMD_i_tree < PMD_Inventory_List_Node_Count; PMD_i_tree++)
                        {

                            //Set up variable flag that we can use later in the for next loop
                            //so that we can determine if a classifiaction already
                            //exist.  If the classification does not exist then the
                            //variable will be "0" indicating that we do not need to add
                            //the classification to the list.
                            PMD_Classification_Exist = 0;

                            //Select the items in the tree for processing
                            if (PMD_Inventory_List.Nodes[PMD_i_tree].Name ==
                               PMD_TP_Classification_To_Store)
                            {
                                //Next add the Ip Address as a child to the classification
                                TreeNode PMD_Inventory_List_Child_To_Add =
                                new TreeNode(PMD_TP_IP_Address_To_Store);
                                //Select the node to be the father to the child
                                PMD_Inventory_List.Nodes[PMD_i_tree].Nodes.Add(PMD_TP_IP_Address_To_Store);

                                //Set the PMD_i_tree equal to PMD_Inventory_List_Node_Count so that we
                                //can exit out of the loop and check if the next item in the
                                //inventory list has an existing catagory
                                PMD_i_tree = PMD_Inventory_List_Node_Count;

                                //Set up variable flag that we can use later
                                //so that we can determine if a classifiaction already
                                //exist.  If the classification does exist then the
                                //variable will be "1" indicating that we need to add
                                //the classification to the list.
                                PMD_Classification_Exist = 1;
                            }
                        }
                        //If we have not found the classification then add
                        //the classification and the IP address to the Tree
                        if (PMD_Classification_Exist == 0)
                        {
                            //This will setup the name of the Node in the tree plus 
                            //the text to be displayed for the node.
                            TreeNode PMD_Inventory_List_Classification = new TreeNode();
                            PMD_Inventory_List_Classification.Name = PMD_TP_Classification_To_Store;
                            PMD_Inventory_List_Classification.Text = PMD_TP_Classification_To_Store;

                            //Set 1
                            PMD_Inventory_List.Nodes.Add(PMD_Inventory_List_Classification);

                            //Since we are now adding one item to the node list we must 
                            //adjust the counter for the number of nodes in the list
                            PMD_Inventory_List_Node_Count =
                                PMD_Inventory_List.Nodes.Count;

                            //Next add the Ip Address as a child to the classification
                            TreeNode PMD_Inventory_List_Child_To_Add =
                                new TreeNode(PMD_TP_IP_Address_To_Store);
                            //Select the node to be the father to the child
                            //Set 1
                            PMD_Inventory_List.Nodes[PMD_Inventory_List_Node_Count - 1].Nodes.Add(PMD_TP_IP_Address_To_Store);

                            //Init the classification variable because we are starting again
                            PMD_Classification_Exist = 0;
                        }


                        //}

                        //Diagnostic message only
                        //MessageBox.Show("PMD_TS16 - Message for halting");

                    }

                    catch
                    {
                        //Diagnostic message only
                        //MessageBox.Show("PMD_TS17 - Message for halting - No Items in Tree or bad selection");

                    }
                }
                else
                {
                    //If we are here it is because there no items (classifictions) in the tree list
                    //and we need to add the first item (classification and IP Address).
                    //First add the classification

                    //This will setup the name of the Node in the tree plus 
                    //the text to be displayed for the node.
                    TreeNode PMD_Inventory_List_Classification = new TreeNode();
                    PMD_Inventory_List_Classification.Name = PMD_TP_Classification_To_Store;
                    PMD_Inventory_List_Classification.Text = PMD_TP_Classification_To_Store;
                    PMD_Inventory_List.Nodes.Add(PMD_Inventory_List_Classification);

                    //Next add the Ip Address as a child to the classification
                    TreeNode PMD_Inventory_List_Child_To_Add =
                        new TreeNode(PMD_TP_IP_Address_To_Store);

                    //Since we are now adding one item to the node list we must 
                    //adjust the counter for the number of nodes in the list
                    PMD_Inventory_List_Node_Count =
                        PMD_Inventory_List.Nodes.Count;

                    //Select the node to be the father to the child
                    //Set 2
                    PMD_Inventory_List.Nodes[PMD_Inventory_List_Node_Count - 1].Nodes.Add(PMD_TP_IP_Address_To_Store);

                    //Diagnostic message only
                    //MessageBox.Show("PMD_TS18 - Message for halting - Tree is empty just added first node");

                }
            }


            //********************************************************************************************************
            //********************************************************************************************************
            //********************************************************************************************************
            //********************************************************************************************************
            //********************************************************************************************************

            ArrayList PMD_Temp_Holding_List = new ArrayList(PMD_Inventory_List.Nodes.Count);
            foreach (TreeNode PMD_ChildNode in PMD_Inventory_List.Nodes)
            {
                //Add the node into the array
                PMD_Temp_Holding_List.Add(PMD_ChildNode);
            }
           
            //Let sort the array by setting to compare each element in the array
            //with all other ellments in the array.
            for (int PMD_Array_Count_1 = 0; PMD_Array_Count_1 <= PMD_Inventory_List.Nodes.Count - 1; PMD_Array_Count_1++)
            {
                //Set up to go through the entire array comparing one ellement with all others.
                for (int PMD_Array_Count_2 = PMD_Array_Count_1; PMD_Array_Count_2 <= PMD_Inventory_List.Nodes.Count - 1; PMD_Array_Count_2++)
                {
                    //Store the node names for so that we can compare them to each other for sorting
                    string PMD_s1 = (PMD_Inventory_List.Nodes[PMD_Array_Count_1].Name) as string;
                    string PMD_s2 = (PMD_Inventory_List.Nodes[PMD_Array_Count_2].Name) as string;

                    //Compare the two location of the major node clasifications.
                    //Test has shown 0 means the values being tested are equal.
                    //If the value is -1 then the first parameter (PMD_s1) is less than
                    //the second parameter(PMD_s2).
                    //If the value is 1 then the first parameter (PMD_s1) is greater than
                    //the second parameter(PMD_s2)

                    //By making the return value test "1" then
                    if (String.Compare(PMD_s1, PMD_s2) == 1)
                    {
                        //Switch the names and text of name displayed of the two values.  Place PMD_s2's value in the 
                        //count 1 location and PMD_s1 inthe 2 location.
                        PMD_Inventory_List.Nodes[PMD_Array_Count_1].Name = PMD_s2;
                        PMD_Inventory_List.Nodes[PMD_Array_Count_2].Name = PMD_s1;
                        PMD_Inventory_List.Nodes[PMD_Array_Count_1].Text = PMD_s2;
                        PMD_Inventory_List.Nodes[PMD_Array_Count_2].Text = PMD_s1;


                        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                        //This will swap the values in the trees that have been sorted
                        //Get the count of the number children count in the first array s1

                        int PMD_Children_Count_s1 =
                            PMD_Inventory_List.Nodes[PMD_Array_Count_1].Nodes.Count;
                        //Set up a for loop to move children in to a temp holding area
                        for (int PMD_Child_Temp_Area_Counter_s1 = 0; PMD_Child_Temp_Area_Counter_s1 < PMD_Children_Count_s1;
                            PMD_Child_Temp_Area_Counter_s1++)
                        {
                            PMD_TP_IP_Address_To_Store_s1[PMD_Child_Temp_Area_Counter_s1] =
                                PMD_Inventory_List.Nodes[PMD_Array_Count_1].Nodes[PMD_Child_Temp_Area_Counter_s1].Text;

                        }

                        //Get the count of the number children count in the second array s2
                        int PMD_Children_Count_s2 =
                            PMD_Inventory_List.Nodes[PMD_Array_Count_2].Nodes.Count;
                        //Set up a for loop to move children in to a temp holding area
                        for (int PMD_Child_Temp_Area_Counter_s2 = 0; PMD_Child_Temp_Area_Counter_s2 < PMD_Children_Count_s2;
                            PMD_Child_Temp_Area_Counter_s2++)
                        {
                            PMD_TP_IP_Address_To_Store_s2[PMD_Child_Temp_Area_Counter_s2] =
                                PMD_Inventory_List.Nodes[PMD_Array_Count_2].Nodes[PMD_Child_Temp_Area_Counter_s2].Text;

                        }

                        //Clear the values in the node sections because we are going to 
                        //Write in new ones
                        PMD_Inventory_List.Nodes[PMD_Array_Count_1].Nodes.Clear();
                        PMD_Inventory_List.Nodes[PMD_Array_Count_2].Nodes.Clear();


                        //Write the array's containing the correct children
                        //back to the tree s1.
                        //But first init a varaible so that we can index in to the array
                        int PMD_while_counter_s1 = 0;

                        while (PMD_TP_IP_Address_To_Store_s2[PMD_while_counter_s1] != null)
                        {
                            PMD_Inventory_List.Nodes[PMD_Array_Count_1].Nodes.Add
                            (PMD_TP_IP_Address_To_Store_s2[PMD_while_counter_s1]);

                            //Increment to get to the next value in the array
                            PMD_while_counter_s1++;
                        }

                        //Write the array's containing the correct children
                        //back to the tree s2.
                        //But first init a varaible so that we can index in to the array
                        int PMD_while_counter_s2 = 0;

                        while (PMD_TP_IP_Address_To_Store_s1[PMD_while_counter_s2] != null)
                        {
                            PMD_Inventory_List.Nodes[PMD_Array_Count_2].Nodes.Add
                            (PMD_TP_IP_Address_To_Store_s1[PMD_while_counter_s2]);

                            //Increment to get to the next value in the array
                            PMD_while_counter_s2++;
                        }

                        //Init the arrays so that we can process the lsit.  You see the 
                        //list of nodes needs to processed many times.

                        for (int PMD_Init_array_counter = 0;
                            PMD_Init_array_counter < 9999;
                            PMD_Init_array_counter++)
                        {
                            PMD_TP_IP_Address_To_Store_s1[PMD_Init_array_counter] = null;
                            PMD_TP_IP_Address_To_Store_s2[PMD_Init_array_counter] = null;
                        }



                        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

                    }
                }
                //This section will order all of the child nodes in ascending order

                //first we must setup to go through each classification (I.E. Node)
                for (int PMD_Array_Count_1b = 0; PMD_Array_Count_1b < PMD_Inventory_List.Nodes.Count; PMD_Array_Count_1b++)
                {
                    //Next we need to set to compare each child node in the list with
                    //its brother and sisters so that we can see where it belongs in the list
                    for (int PMD_Child_Node_1 = 0;
                        PMD_Child_Node_1 < PMD_Inventory_List.Nodes[PMD_Array_Count_1b].Nodes.Count;
                        PMD_Child_Node_1++)
                    {
                        //Interesting fact - we can not make this "0" which is tradition we need to 
                        //make sure that we compare each successive slot for child 1 or we get an
                        //infinite loop because values that are check never not greatwer than
                        //thier slot position.
                        for (int PMD_Child_Node_2 = PMD_Child_Node_1;
                        PMD_Child_Node_2 < PMD_Inventory_List.Nodes[PMD_Array_Count_1b].Nodes.Count;
                        PMD_Child_Node_2++)
                        {

                            //Store the node child names so that we can compare them to each other for sorting
                            string PMD_Child_Node_c1 =
                                (PMD_Inventory_List.Nodes[PMD_Array_Count_1b].Nodes[PMD_Child_Node_1].Text) as string;
                            string PMD_Child_Node_c2 =
                                (PMD_Inventory_List.Nodes[PMD_Array_Count_1b].Nodes[PMD_Child_Node_2].Text) as string;

                            //This will temp hold one of the values being swapped for the below 
                            //If compare of the two child values
                            string PMD_Child_Node_Temp_Holding = null;


                            //Compare the two location of the child nodes for a particular clasifications.
                            //Test has shown 0 means the values being tested are equal.
                            //If the value is -1 then the first parameter (PMD_Child_Node_c1) is less than
                            //the second parameter(PMD_Child_Node_c2).
                            //If the value is 1 then the first parameter (PMD_Child_Node_c1) is greater than
                            //the second parameter(PMD_Child_Node_c2)

                            //By making the return value test "1" then swap position of the two
                            //child nodes
                            if (String.Compare(PMD_Child_Node_c1, PMD_Child_Node_c2) == 1)
                            {
                                //Init the temp holding varailble for the swap
                                PMD_Child_Node_Temp_Holding = null;

                                //Step 1 - store the value being compared to in the 
                                //temp variable
                                PMD_Child_Node_Temp_Holding = PMD_Child_Node_c1;
                                //Step 2 - store the value of the child node node in the spot
                                //that we found to be less than the value being compared to
                                PMD_Inventory_List.Nodes[PMD_Array_Count_1b].Nodes[PMD_Child_Node_1].Text =
                                    PMD_Child_Node_c2;
                                //Step 3 store the temp variable in to the other location
                                //where the child node should be greater that the value
                                //stored in the original location
                                PMD_Inventory_List.Nodes[PMD_Array_Count_1b].Nodes[PMD_Child_Node_2].Text =
                                    PMD_Child_Node_Temp_Holding;
                                //Step 4 -  We must now break the loop for the inner check and start from the 
                                //begining of both loops.
                                PMD_Child_Node_2 = PMD_Inventory_List.Nodes[PMD_Array_Count_1b].Nodes.Count;
                                PMD_Child_Node_1 = -1;
                                                           }
                        }
                    }
                }
            }
         }

        private void PMD_Inventory_List_AfterSelect(object sender, TreeViewEventArgs e)
        {

        }

        private void PMD_Inventory_List_AfterSelect_1(object sender, TreeViewEventArgs e)
        {
            //Store the node that has been selectect in the global variable
            PMD_TUODPR_Single_Selected_Node = PMD_Inventory_List.SelectedNode.Text;
        }

        private void displayDeviceResponseChartToolStripMenuItem_Click(object sender, EventArgs e)
        {
                      
            //Get this devices response info
            Snap_Shot_Of_One_Devices_Ping_Responses();

                      
        }

        private void Snap_Shot_Of_One_Devices_Ping_Responses()
        {
            //Reset the chart veiw and hide the button
            //Reset the chart Access
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisX.View.ZoomReset(0);
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisY.View.ZoomReset(0);
                        
            //Clear the chart out
            Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"].Points.Clear();

                       
            //this is the initial read of the devices data
            //this will set the first right of the graph
            //This will build/rebuild the inventory display list
            //
            //*******************************************************************
            //First check to see if the inventory data file exist
            //We need a flag value to indicate if the file exist
            //or is there is a problem openning it when we try to test 
            //for the main data file in the Phoenix utility.  If the file does
            //not exist it is created.  Either way we must check for problems.
            //this is a boolean value by making the default value "false"
            try
            {
                //Open the file top see if error is generated
                using (FileStream PMD_TP_fs = new FileStream
                    ("\\Phoenix\\PingScans\\Phoenix_PingScans.txt", FileMode.OpenOrCreate))
                {
                    //Guess what.....The file has been either openned 
                    //or created successfully.  Now make sure that it is closed
                    PMD_TP_fs.Close();
                }

            }
            catch (IOException IFO_ex)
            {
                //If we can not access or create the file 
                //and we get an error.  Display the error and
                //halt the program.
                String PMD_TP_File_Exist_Message = IFO_ex.Message.ToString();
                MessageBox.Show("PMD_TP15 - " +
                    PMD_TP_File_Exist_Message + " It is being created");

                //Try creating the inventory file in case it does not exist
                try
                {
                    //Create the file with the path
                    File.CreateText("\\Phoenix\\PingScans\\Phoenix_PingScans.txt");

                }
                catch (IOException IFO_ex1)
                {
                    //If we can not access or create the file 
                    //and we get an error.  Display the error and
                    //halt the program.
                    String PMD_TP_File_Exist_Message1 = IFO_ex1.Message.ToString();
                    MessageBox.Show("PMD_TP16 - Error creating main inventory data file.  Error - " +
                    PMD_TP_File_Exist_Message1);
                }


                //Exit Phoenix.  We should put in error handling code for the 
                //exception.  First we will need to figure out what Exceptions
                //are needed.
                Application.Exit();
            }

            //===================================================================================
            //===================================================================================
            //First get the number of records in the data file

            //Open the datafile for a read of all of the existing data
            //so that we can compare what is discovered with what is already
            //in the datafile.

            try
            {
                using (System.IO.StreamReader PMD_TP_Open_Phoenix_PingScan_File =
                        File.OpenText("\\Phoenix\\PingScans\\Phoenix_PingScans.txt"))
                {

                    //set up a variable to read records from 
                    //the Phoenix inventory data file.  I picked a
                    //a number of 10000 as the maximum number of records
                    //that is certainy past the limmit of a small network
                    //string[] PMD_TP_Record_to_Compare = new string[10000];


                    //This section inits the varaible that holds the records
                    //an makes the entire array null
                    for (int PMD_TP_Init_Record_Counter = 0; PMD_TP_Init_Record_Counter < 10000; PMD_TP_Init_Record_Counter++)
                    {
                        //init the slot in the array
                        PMD_TP_Device_to_Scan_For[PMD_TP_Init_Record_Counter] = "";
                    }
                    
                    //Init the counter of the records
                    PMD_TP_Phoenix_Records_In_PingScan_DB = 0;

                    //Start reading the data from the file
                    while ((PMD_TP_Device_Ping_Response_Data[PMD_TP_Phoenix_Records_In_Inventory_DB] =
                        PMD_TP_Open_Phoenix_PingScan_File.ReadLine()) != null)
                    {
                        PMD_TP_Phoenix_Records_In_PingScan_DB = PMD_TP_Phoenix_Records_In_Inventory_DB + 1;
                        if (PMD_TP_Phoenix_Records_In_PingScan_DB >= 9999)
                        {
                            MessageBox.Show("PMD_TP11 - Maximum number of 10000 records reached.  This is temp limit and fixed later");
                        }
                    }
                }
            }
            catch (IOException IFO_ex)
            {
                //If we can not access or create the file 
                //and we get an error.  Display the error and
                //halt the program.
                String PMD_TP_File_Exist_Message = IFO_ex.Message.ToString();
                MessageBox.Show("PMD_TS12 - Error openning main inventory data file.  Error - " +
                PMD_TP_File_Exist_Message);


                //Exit Phoenix.  We should put in error handling code for the 
                //exception.  First we will need to figure out what Exceptions
                //are needed.
                Application.Exit();
            }

            //Test message to show the number of records read
            //MessageBox.Show("PMD_TP3 - Number of records read is " + PMD_TP_Phoenix_Records_In_Inventory_DB);

            //If there are not any records in the inventory file no
            //sense to process any thing else so exit out of utility
            if (PMD_TP_Phoenix_Records_In_PingScan_DB == 0)
            {

                MessageBox.Show("PMD_TP14 - Warning - There are no records in the main inventory file to display");

                //exit our of routine
                return;
            }

            //First find which device is selected from the list.
            PMD_TP_Single_Selected_Node = PMD_Inventory_List.SelectedNode.Text;
            //MessageBox.Show(PMD_TP_Single_Selected_Node);
            
            //Loop through the database to determine the records that 
            //have the IP address we need.

            //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
            //This section will go through the entire database and store only the record
            //that is the IP address selected by the user.
            
            try
            {
                using (System.IO.StreamReader PMD_TP_Open_Phoenix_PingScan_File =
                        File.OpenText("\\Phoenix\\PingScans\\Phoenix_PingScans.txt"))
                {

                    //public static string[] PMD_TP_Device_Response_Time = new string[100000];
                    //public static int PMD_TP_Phoenix_Number_Of_Response_Time_Records = 0;
                    
                    //set up a variable to read records from 
                    //the Phoenix inventory data file.  I picked a
                    //a number of 10000 as the maximum number of records
                    //that is certainy past the limmit of a small network
                    //string[] PMD_TP_Record_to_Compare = new string[10000];


                    //Init the temp variable that hold the record for processing
                    PMD_TP_Device_Ping_Response_Data_Temp_Holding = "";
                    
                    //This section inits the varaible that holds the records
                    //an makes the entire array null
                    for (int PMD_TP_Init_Record_To_Store_Counter = 0; PMD_TP_Init_Record_To_Store_Counter < 100000; PMD_TP_Init_Record_To_Store_Counter++)
                    {
                        //init the slot in the array
                        PMD_TP_Device_Response_Time[PMD_TP_Init_Record_To_Store_Counter] = "";
                                            }

                    //Init the counter of the records
                    PMD_TP_Phoenix_Records_In_PingScan_DB = 0;

                    //init the value that stores the counter for number of 
                    //datapoints on the graph
                    int PMD_SSOODPR_number_of_xseries_DP=0;

                    //Start reading the data from the file
                    while ((PMD_TP_Device_Ping_Response_Data_Temp_Holding =
                        PMD_TP_Open_Phoenix_PingScan_File.ReadLine()) != null)
                    {
                        PMD_TP_Phoenix_Records_In_PingScan_DB = PMD_TP_Phoenix_Records_In_Inventory_DB + 1;
                        
                        //Next see if this record contains the IP address that the 
                        //user has selected.
                        //init the vairable that would contain a value greater than
                        //-1 if we found the text the user has selected
                        int PMD_TP_Index=0;
                                             
                        //check for the IP address the user selected
                        PMD_TP_Index = PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                            (PMD_Inventory_List.SelectedNode.Text);

                        if (PMD_TP_Index == -1 || PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                            (",", (PMD_TP_Index + PMD_Inventory_List.SelectedNode.Text.Length), 1) == -1)
                        {
                            //MessageBox.Show("NO HIT");
                        }
                        else
                        {
                            //If we get to this point we have found the record in the 
                            //inventory file that we need.  Now we must extract the 
                            //if the ping was successfull.  If we find the phase Ping Result:Success or 
                            //the phase Ping Result:TimedOut for the times we we can not find the Success
                            //in the record then record the time
                            int PMD_TP_Index_Ping_Result = 0;
                            PMD_TP_Index_Ping_Result = PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                            ("Ping Result:Success");

                            if ((PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                ("Ping Result:Success") != -1) ^ (PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                ("Ping Result:TimedOut") != -1))
                            {
                                //Find the value for the repsonse time of the ping
                                //Get the value by finding the phrase "Ping Return Time: 
                                //Step one: Find where the ping return data is in the 
                                //record
                                int PMD_SSOODPR_Ping_Response_In_Record = 0;
                                PMD_SSOODPR_Ping_Response_In_Record =
                                    PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf("Ping Return Time:") + 1;

                                //Find the location of the first comma "," after the ping return time
                                int PMD_SSOODPR_Comma_After_Ping_Return_Time = 0;
                                PMD_SSOODPR_Comma_After_Ping_Return_Time =
                                    PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                    (",", PMD_SSOODPR_Ping_Response_In_Record);

                                //Note that we must determine the number of digits that the 
                                //return time is.  This is done by taking the location of the comma
                                //after the return time and subtracting the starting location of
                                //"Ping Return Time Text" plus 7 which equals the location just
                                //before the start of the Ping Return digits.
                                //There may be a better way to do this but this seems good for now.
                                int PMD_SSOODPR_Comma_After_Ping_Return_Time_Length = 0;
                                PMD_SSOODPR_Comma_After_Ping_Return_Time_Length =
                                    ((PMD_SSOODPR_Comma_After_Ping_Return_Time) -
                                    (PMD_SSOODPR_Ping_Response_In_Record + 16));

                                //Parse the record and store the string in a variable
                                string PMD_SSOODPR_Ping_Return_Time_String = "";
                                PMD_SSOODPR_Ping_Return_Time_String =
                                    PMD_TP_Device_Ping_Response_Data_Temp_Holding.Substring
                                    (PMD_SSOODPR_Ping_Response_In_Record + 16, PMD_SSOODPR_Comma_After_Ping_Return_Time_Length);

                                //Next convert the string value to an integer
                                int PMD_SSOODPR_Ping_Return_Time_Integer = 0;
                                PMD_SSOODPR_Ping_Return_Time_Integer =
                                    Convert.ToInt32(PMD_SSOODPR_Ping_Return_Time_String);

                                //indcrement the counter that holds the number of data points
                                //in the graph
                                PMD_SSOODPR_number_of_xseries_DP =
                                    PMD_SSOODPR_number_of_xseries_DP + 1;



                                //This next section changes the chart title to 
                                //reflect what we are looking at
                                Snap_Shot_Device_Response_Chart.Titles[0].Font =
                                    new Font("Times New Roman", 12, FontStyle.Bold);

                                //Set the Font color
                                Snap_Shot_Device_Response_Chart.Titles[0].Color =
                                    Color.SteelBlue;

                                //Set the Font color
                                Snap_Shot_Device_Response_Chart.Titles[0].BackColor =
                                    Color.Transparent;

                                //Change the chart title to reflect the Snap shot optione
                                //and IP address we are looking at.
                                Snap_Shot_Device_Response_Chart.Titles[0].Text =
                                    "Snap Shot Of Ping Results For "
                                    + PMD_Inventory_List.SelectedNode.Text
                                    + "\n"
                                    + "Report Run Date "
                                    + DateTime.Now.ToLongDateString();



                                //Find the value for the date of the ping
                                //Get the value by finding the phrase "DATE: 
                                //Step one: Find where the ping return DATE is in the 
                                //record
                                int PMD_SSOODPR_Ping_DATE_In_Record = 0;
                                PMD_SSOODPR_Ping_DATE_In_Record =
                                    PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf("DATE:");

                                //Find the location of the first comma "," after the ping return time
                                int PMD_SSOODPR_Comma_After_Ping_Return_DATE = 0;
                                PMD_SSOODPR_Comma_After_Ping_Return_DATE =
                                    PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                    (",", PMD_SSOODPR_Ping_DATE_In_Record);

                                //Note that we must determine the number of digits that the 
                                //ping DATE is.  This is done by taking the location of the comma
                                //after the ping DATE and subtracting the starting location of
                                //"Ping DATE Text" plus 5 which equals the location just
                                //before the start of the Ping DATE digits.
                                //There may be a better way to do this but this seems good for now.
                                int PMD_SSOODPR_Comma_After_Ping_DATE_Length = 0;
                                PMD_SSOODPR_Comma_After_Ping_DATE_Length =
                                    ((PMD_SSOODPR_Comma_After_Ping_Return_DATE) -
                                    (PMD_SSOODPR_Ping_DATE_In_Record + 5));

                                //Parse the record and store the string in a variable
                                string PMD_SSOODPR_Ping_Return_DATE_String = "";
                                PMD_SSOODPR_Ping_Return_DATE_String =
                                    PMD_TP_Device_Ping_Response_Data_Temp_Holding.Substring
                                    ((PMD_SSOODPR_Ping_DATE_In_Record + 5), PMD_SSOODPR_Comma_After_Ping_DATE_Length);


                                //Find the value for the TIME of the ping
                                //Get the value by finding the phrase "TIME: 
                                //Step one: Find where the ping return TIME is in the 
                                //record
                                int PMD_SSOODPR_Ping_TIME_In_Record = 0;
                                PMD_SSOODPR_Ping_TIME_In_Record =
                                    PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf("TIME:");

                                //Find the location of the first comma "," after the ping return time
                                int PMD_SSOODPR_Comma_After_Ping_Return_TIME = 0;
                                PMD_SSOODPR_Comma_After_Ping_Return_TIME =
                                    PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                    (",", PMD_SSOODPR_Ping_TIME_In_Record);

                                //Note that we must determine the number of digits that the 
                                //ping TIME is.  This is done by taking the location of the comma
                                //after the ping TIME and subtracting the starting location of
                                //"Ping TIME Text" plus 5 which equals the location just
                                //before the start of the Ping TIME digits.
                                //There may be a better way to do this but this seems good for now.
                                int PMD_SSOODPR_Comma_After_Ping_TIME_Length = 0;
                                PMD_SSOODPR_Comma_After_Ping_TIME_Length =
                                    ((PMD_SSOODPR_Comma_After_Ping_Return_TIME) -
                                    (PMD_SSOODPR_Ping_TIME_In_Record + 5));

                                //Parse the record and store the string in a variable
                                string PMD_SSOODPR_Ping_Return_TIME_String = "";
                                PMD_SSOODPR_Ping_Return_TIME_String =
                                    PMD_TP_Device_Ping_Response_Data_Temp_Holding.Substring
                                    ((PMD_SSOODPR_Ping_TIME_In_Record + 5), PMD_SSOODPR_Comma_After_Ping_TIME_Length);

                                //This section does the date extract from the record and
                                //formats it for the chart
                                //This is a test to see if we can get the date and time in to the
                                //chart X-Axis.
                                string PMD_SSOODPR_X_Axis_Date_and_Time = "";
                                PMD_SSOODPR_X_Axis_Date_and_Time = PMD_SSOODPR_Ping_Return_DATE_String
                                    + "\n" + PMD_SSOODPR_Ping_Return_TIME_String;



                                if ((PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                ("Ping Result:Success") != -1))
                                {

                                    //Add data to the "Successful Pings" series "SS_Ping_Response" in the chart
                                    //the X values will be the record number and the Y values will be the 
                                    //ping responce that we recived from the device/www/DNS name sites
                                    Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"]
                                        .Points.AddXY(PMD_SSOODPR_X_Axis_Date_and_Time, PMD_SSOODPR_Ping_Return_Time_Integer);

                                    //Add data to the "SS_Ping_Timeout" series in the chart.
                                    //In this case the there will be a value for a successfull ping reponse
                                    //so the "timeout" value will be zero.
                                    //the X values will be the record number and the Y values will be the 
                                    //ping responce that we recived from the device/www/DNS name sites
                                    Snap_Shot_Device_Response_Chart.Series["SS_Ping_Timeout"]
                                        .Points.AddXY(PMD_SSOODPR_X_Axis_Date_and_Time, 0);

                                }

                                if ((PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                ("Ping Result:TimedOut") != -1))
                                {

                                    //Add data to the "Successful Pings" series "SS_Ping_Response" in the chart.
                                    //In this case the there will be a value for a timed out ping reponse
                                    //so the "suceess" value will be zero value will be zero.
                                    //the X values will be the record number and the Y values will be the 
                                    //ping responce that we recived from the device/www/DNS name sites
                                    Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"]
                                        .Points.AddXY(PMD_SSOODPR_X_Axis_Date_and_Time, 0);

                                    //Add data to the "SS_Ping_Timeout" series in the chart.
                                    //In this case the there will be a value for a successfull ping reponse
                                    //so the "timeout" value will be zero.
                                    //the X values will be the record number and the Y values will be the 
                                    //ping responce that we recived from the device/www/DNS name sites
                                    Snap_Shot_Device_Response_Chart.Series["SS_Ping_Timeout"]
                                        .Points.AddXY(PMD_SSOODPR_X_Axis_Date_and_Time, PMD_SSOODPR_Ping_Return_Time_Integer);

                                }

                                //Reset the chart Access
                                Snap_Shot_Device_Response_Chart.ResetAutoValues();

                                //Reset the chart Access
                                Snap_Shot_Device_Response_Chart.Visible = true;
                                Snap_Shot_Device_Response_Chart.Enabled = true;
                                //Make the chart reset button visible
                                PMD_Chart_Reset_Button.Visible = true;
                                



                            }
                            
                            
                            







                        }
                      }
                    
                                     
                        if (PMD_TP_Phoenix_Records_In_PingScan_DB >= 99999)
                        {
                            MessageBox.Show("PMD_TP11 - Maximum number of 100000 records reached.  This is temp limit and fixed later");
                        }
                    }
                }
            
            catch (IOException IFO_ex)
            {
                //If we can not access or create the file 
                //and we get an error.  Display the error and
                //halt the program.
                String PMD_TP_File_Exist_Message = IFO_ex.Message.ToString();
                MessageBox.Show("PMD_TS12 - Error openning main inventory data file.  Error - " +
                PMD_TP_File_Exist_Message);


                //Exit Phoenix.  We should put in error handling code for the 
                //exception.  First we will need to figure out what Exceptions
                //are needed.
                Application.Exit();
            }

            //MessageBox.Show("Completed Charting");



        }

        private void Snap_Shot_Device_Response_Chart_Click(object sender, EventArgs e)
        {
            //Show the Reset Chart view button
            PMD_Chart_Reset_Button.Visible = true;

        }

        private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {

        }

        private void PMD_Chart_Start_Value_Scroll(object sender, ScrollEventArgs e)
        {
            //




        }

        

        private void PMD_Context_Menu_Opening(object sender, CancelEventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        private void PMD_Chart_Reset_Button_Click(object sender, EventArgs e)
        {
            //Reset the chart veiw and hide the button
            //Reset the chart Access
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisX.View.ZoomReset(0);
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisY.View.ZoomReset(0);


           


        }
        private void PMD_Ping_Set_Timed_Update_Entire_Data_Set(int PMD_Ping_Expire_Time)
        {
            //First record the highlighted item in a global variable
            //First find which device is selected from the list.
            PMD_TUODPR_Single_Selected_Node = PMD_Inventory_List.SelectedNode.Text;
            
            
            //This routine will update the entire data set
            //for the selected device.
            if (PMD_Ping_Expire_Time == 0)
            {
                MessageBox.Show("PMD_0905091854 - PMD_Ping_Expire_Time was set\to zero accidently, resetting it to 30 seconds");

                //set time to 30 seconds
                PMD_Ping_Expire_Time = 30000;
              
            }

            //Set the global variable so that we can display the ping expirery interval
            PMD_Ping_Expire_Time_Global = PMD_Ping_Expire_Time;
                
                //First set the timer interval
            PMD_Ping_Display_Update_Timer = new System.Timers.Timer(PMD_Ping_Expire_Time);

            //Set the utility to to run when the timer expires
            //PMD_Ping_Display_Update_Timer.Elapsed +=new ElapsedEventHandler(PMD_Ping_Entire_Dataset_Update);
            PMD_Ping_Display_Update_Timer.Elapsed += new ElapsedEventHandler(PMD_Ping_Entire_Dataset_Update);
            
                      
            
            PMD_Ping_Display_Update_Timer.Enabled=true;
        
        }

        private void PMD_Ping_Entire_Dataset_Update(object source, ElapsedEventArgs e)
        {
            //When the timer expires this routine is executed

            //First disable the timer
            PMD_Ping_Display_Update_Timer.Enabled = false;

            //########################################################################################
            //########################################################################################
            //Added per expert exchange 12/30/09 12:50pm
            //This will set up the backgroud worker task
            worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            worker.RunWorkerAsync();


            //Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisX.View.ZoomReset(0);
            //Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisY.View.ZoomReset(0);
            
            
                //Clear the chart out
                Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"].Points.Clear();


                //this is the initial read of the devices data
                //this will set the first right of the graph
                //This will build/rebuild the inventory display list
                //
                //*******************************************************************
                //First check to see if the inventory data file exist
                //We need a flag value to indicate if the file exist
                //or is there is a problem openning it when we try to test 
                //for the main data file in the Phoenix utility.  If the file does
                //not exist it is created.  Either way we must check for problems.
                //this is a boolean value by making the default value "false"
                try
                {
                    //Open the file top see if error is generated
                    using (FileStream PMD_TP_fs = new FileStream
                        ("\\Phoenix\\PingScans\\Phoenix_PingScans.txt", FileMode.OpenOrCreate))
                    {
                        //Guess what.....The file has been either openned 
                        //or created successfully.  Now make sure that it is closed
                        PMD_TP_fs.Close();
                    }

                }
                catch (IOException IFO_ex)
                {
                    //If we can not access or create the file 
                    //and we get an error.  Display the error and
                    //halt the program.
                    String PMD_TP_File_Exist_Message = IFO_ex.Message.ToString();
                    MessageBox.Show("PMD_TP15 - " +
                        PMD_TP_File_Exist_Message + " It is being created");

                    //Try creating the inventory file in case it does not exist
                    try
                    {
                        //Create the file with the path
                        File.CreateText("\\Phoenix\\PingScans\\Phoenix_PingScans.txt");
                       

                    }
                    catch (IOException IFO_ex1)
                    {
                        //If we can not access or create the file 
                        //and we get an error.  Display the error and
                        //halt the program.
                        String PMD_TP_File_Exist_Message1 = IFO_ex1.Message.ToString();
                        MessageBox.Show("PMD_TP16 - Error creating main inventory data file.  Error - " +
                        PMD_TP_File_Exist_Message1);
                    }


                    //Exit Phoenix.  We should put in error handling code for the 
                    //exception.  First we will need to figure out what Exceptions
                    //are needed.
                    Application.Exit();
                }

                //===================================================================================
                //===================================================================================
                //First get the number of records in the data file

                //Open the datafile for a read of all of the existing data
                //so that we can compare what is discovered with what is already
                //in the datafile.

                try
                {
                    using (System.IO.StreamReader PMD_TP_Open_Phoenix_PingScan_File =
                            File.OpenText("\\Phoenix\\PingScans\\Phoenix_PingScans.txt"))
                    {

                        //set up a variable to read records from 
                        //the Phoenix inventory data file.  I picked a
                        //a number of 10000 as the maximum number of records
                        //that is certainy past the limmit of a small network
                        //string[] PMD_TP_Record_to_Compare = new string[10000];


                        //This section inits the varaible that holds the records
                        //an makes the entire array null
                        for (int PMD_TP_Init_Record_Counter = 0; PMD_TP_Init_Record_Counter < 10000; PMD_TP_Init_Record_Counter++)
                        {
                            //init the slot in the array
                            PMD_TP_Device_to_Scan_For[PMD_TP_Init_Record_Counter] = "";
                        }

                        //Init the counter of the records
                        PMD_TP_Phoenix_Records_In_PingScan_DB = 0;

                        //Start reading the data from the file
                        while ((PMD_TP_Device_Ping_Response_Data[PMD_TP_Phoenix_Records_In_Inventory_DB] =
                            PMD_TP_Open_Phoenix_PingScan_File.ReadLine()) != null)
                        {
                            PMD_TP_Phoenix_Records_In_PingScan_DB = PMD_TP_Phoenix_Records_In_Inventory_DB + 1;
                            if (PMD_TP_Phoenix_Records_In_PingScan_DB >= 9999)
                            {
                                MessageBox.Show("PMD_TP11 - Maximum number of 10000 records reached.  This is temp limit and fixed later");
                            }
                        }
                    }
                }
                catch (IOException IFO_ex)
                {
                    //If we can not access or create the file 
                    //and we get an error.  Display the error and
                    //halt the program.
                    String PMD_TP_File_Exist_Message = IFO_ex.Message.ToString();
                    MessageBox.Show("PMD_TS12 - Error openning main inventory data file.  Error - " +
                    PMD_TP_File_Exist_Message);


                    //Exit Phoenix.  We should put in error handling code for the 
                    //exception.  First we will need to figure out what Exceptions
                    //are needed.
                    Application.Exit();
                }

                //Test message to show the number of records read
                //MessageBox.Show("PMD_TP3 - Number of records read is " + PMD_TP_Phoenix_Records_In_Inventory_DB);

                //If there are not any records in the inventory file no
                //sense to process any thing else so exit out of utility
                if (PMD_TP_Phoenix_Records_In_PingScan_DB == 0)
                {

                    MessageBox.Show("PMD_TP14 - Warning - There are no records in the main inventory file to display");

                    //exit our of routine
                    return;
                }

                //First find which device is selected from the list.
                //This is already known through the global variable PMD_TP_Single_Selected_Node = PMD_Inventory_List.SelectedNode.Text;
                //MessageBox.Show(PMD_TP_Single_Selected_Node);

                //Loop through the database to determine the records that 
                //have the IP address we need.

                //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                //This section will go through the entire database and store only the record
                //that is the IP address selected by the user.

                try
                {
                    using (System.IO.StreamReader PMD_TP_Open_Phoenix_PingScan_File =
                            File.OpenText("\\Phoenix\\PingScans\\Phoenix_PingScans.txt"))
                    

                    {

                        //public static string[] PMD_TP_Device_Response_Time = new string[100000];
                        //public static int PMD_TP_Phoenix_Number_Of_Response_Time_Records = 0;

                        //set up a variable to read records from 
                        //the Phoenix inventory data file.  I picked a
                        //a number of 10000 as the maximum number of records
                        //that is certainy past the limmit of a small network
                        //string[] PMD_TP_Record_to_Compare = new string[10000];


                        //Init the temp variable that hold the record for processing
                        PMD_TP_Device_Ping_Response_Data_Temp_Holding = "";

                        //This section inits the varaible that holds the records
                        //an makes the entire array null
                        for (int PMD_TP_Init_Record_To_Store_Counter = 0; PMD_TP_Init_Record_To_Store_Counter < 100000; PMD_TP_Init_Record_To_Store_Counter++)
                        {
                            //init the slot in the array
                            PMD_TP_Device_Response_Time[PMD_TP_Init_Record_To_Store_Counter] = "";
                        }

                        //Init the counter of the records
                        PMD_TP_Phoenix_Records_In_PingScan_DB = 0;

                        //init the value that stores the counter for number of 
                        //datapoints on the graph
                        int PMD_SSOODPR_number_of_xseries_DP = 0;

                        //Start reading the data from the file
                        while ((PMD_TP_Device_Ping_Response_Data_Temp_Holding =
                            PMD_TP_Open_Phoenix_PingScan_File.ReadLine()) != null)
                        {
                            PMD_TP_Phoenix_Records_In_PingScan_DB = PMD_TP_Phoenix_Records_In_Inventory_DB + 1;

                            //Next see if this record contains the IP address that the 
                            //user has selected.
                            //init the vairable that would contain a value greater than
                            //-1 if we found the text the user has selected
                            int PMD_TP_Index = 0;

                            //check for the IP address the user selected
                            PMD_TP_Index = PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                (PMD_TP_Single_Selected_Node);

                            if (PMD_TP_Index == -1 || PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                (",", (PMD_TP_Index + PMD_TP_Single_Selected_Node.Length), 1) == -1)
                            {
                                //MessageBox.Show("NO HIT");
                            }
                            else
                            {
                                //If we get to this point we have found the record in the 
                                //inventory file that we need.  Now we must extract the 
                                //if the ping was successfull.  If we find the phase Ping Result:Success or 
                                //the phase Ping Result:TimedOut for the times we we can not find the Success
                                //in the record then record the time
                                int PMD_TP_Index_Ping_Result = 0;
                                PMD_TP_Index_Ping_Result = PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                ("Ping Result:Success");

                                if ((PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                    ("Ping Result:Success") != -1) ^ (PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                    ("Ping Result:TimedOut") != -1))
                                {
                                    //Find the value for the repsonse time of the ping
                                    //Get the value by finding the phrase "Ping Return Time: 
                                    //Step one: Find where the ping return data is in the 
                                    //record
                                    int PMD_SSOODPR_Ping_Response_In_Record = 0;
                                    PMD_SSOODPR_Ping_Response_In_Record =
                                        PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf("Ping Return Time:") + 1;

                                    //Find the location of the first comma "," after the ping return time
                                    int PMD_SSOODPR_Comma_After_Ping_Return_Time = 0;
                                    PMD_SSOODPR_Comma_After_Ping_Return_Time =
                                        PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                        (",", PMD_SSOODPR_Ping_Response_In_Record);

                                    //Note that we must determine the number of digits that the 
                                    //return time is.  This is done by taking the location of the comma
                                    //after the return time and subtracting the starting location of
                                    //"Ping Return Time Text" plus 7 which equals the location just
                                    //before the start of the Ping Return digits.
                                    //There may be a better way to do this but this seems good for now.
                                    int PMD_SSOODPR_Comma_After_Ping_Return_Time_Length = 0;
                                    PMD_SSOODPR_Comma_After_Ping_Return_Time_Length =
                                        ((PMD_SSOODPR_Comma_After_Ping_Return_Time) -
                                        (PMD_SSOODPR_Ping_Response_In_Record + 16));

                                    //Parse the record and store the string in a variable
                                    string PMD_SSOODPR_Ping_Return_Time_String = "";
                                    PMD_SSOODPR_Ping_Return_Time_String =
                                        PMD_TP_Device_Ping_Response_Data_Temp_Holding.Substring
                                        (PMD_SSOODPR_Ping_Response_In_Record + 16, PMD_SSOODPR_Comma_After_Ping_Return_Time_Length);

                                    //Next convert the string value to an integer
                                    int PMD_SSOODPR_Ping_Return_Time_Integer = 0;
                                    PMD_SSOODPR_Ping_Return_Time_Integer =
                                        Convert.ToInt32(PMD_SSOODPR_Ping_Return_Time_String);

                                    //indcrement the counter that holds the number of data points
                                    //in the graph
                                    PMD_SSOODPR_number_of_xseries_DP =
                                        PMD_SSOODPR_number_of_xseries_DP + 1;



                                    //Find the value for the date of the ping
                                    //Get the value by finding the phrase "DATE: 
                                    //Step one: Find where the ping return DATE is in the 
                                    //record
                                    int PMD_SSOODPR_Ping_DATE_In_Record = 0;
                                    PMD_SSOODPR_Ping_DATE_In_Record =
                                        PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf("DATE:");

                                    //Find the location of the first comma "," after the ping return time
                                    int PMD_SSOODPR_Comma_After_Ping_Return_DATE = 0;
                                    PMD_SSOODPR_Comma_After_Ping_Return_DATE =
                                        PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                        (",", PMD_SSOODPR_Ping_DATE_In_Record);

                                    //Note that we must determine the number of digits that the 
                                    //ping DATE is.  This is done by taking the location of the comma
                                    //after the ping DATE and subtracting the starting location of
                                    //"Ping DATE Text" plus 5 which equals the location just
                                    //before the start of the Ping DATE digits.
                                    //There may be a better way to do this but this seems good for now.
                                    int PMD_SSOODPR_Comma_After_Ping_DATE_Length = 0;
                                    PMD_SSOODPR_Comma_After_Ping_DATE_Length =
                                        ((PMD_SSOODPR_Comma_After_Ping_Return_DATE) -
                                        (PMD_SSOODPR_Ping_DATE_In_Record + 5));

                                    //Parse the record and store the string in a variable
                                    string PMD_SSOODPR_Ping_Return_DATE_String = "";
                                    PMD_SSOODPR_Ping_Return_DATE_String =
                                        PMD_TP_Device_Ping_Response_Data_Temp_Holding.Substring
                                        ((PMD_SSOODPR_Ping_DATE_In_Record + 5), PMD_SSOODPR_Comma_After_Ping_DATE_Length);


                                    //Find the value for the TIME of the ping
                                    //Get the value by finding the phrase "TIME: 
                                    //Step one: Find where the ping return TIME is in the 
                                    //record
                                    int PMD_SSOODPR_Ping_TIME_In_Record = 0;
                                    PMD_SSOODPR_Ping_TIME_In_Record =
                                        PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf("TIME:");

                                    //Find the location of the first comma "," after the ping return time
                                    int PMD_SSOODPR_Comma_After_Ping_Return_TIME = 0;
                                    PMD_SSOODPR_Comma_After_Ping_Return_TIME =
                                        PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                        (",", PMD_SSOODPR_Ping_TIME_In_Record);

                                    //Note that we must determine the number of digits that the 
                                    //ping TIME is.  This is done by taking the location of the comma
                                    //after the ping TIME and subtracting the starting location of
                                    //"Ping TIME Text" plus 5 which equals the location just
                                    //before the start of the Ping TIME digits.
                                    //There may be a better way to do this but this seems good for now.
                                    int PMD_SSOODPR_Comma_After_Ping_TIME_Length = 0;
                                    PMD_SSOODPR_Comma_After_Ping_TIME_Length =
                                        ((PMD_SSOODPR_Comma_After_Ping_Return_TIME) -
                                        (PMD_SSOODPR_Ping_TIME_In_Record + 5));

                                    //Parse the record and store the string in a variable
                                    string PMD_SSOODPR_Ping_Return_TIME_String = "";
                                    PMD_SSOODPR_Ping_Return_TIME_String =
                                        PMD_TP_Device_Ping_Response_Data_Temp_Holding.Substring
                                        ((PMD_SSOODPR_Ping_TIME_In_Record + 5), PMD_SSOODPR_Comma_After_Ping_TIME_Length);

                                    //This section does the date extract from the record and
                                    //formats it for the chart
                                    //This is a test to see if we can get the date and time in to the
                                    //chart X-Axis.
                                    string PMD_SSOODPR_X_Axis_Date_and_Time = "";
                                    PMD_SSOODPR_X_Axis_Date_and_Time = PMD_SSOODPR_Ping_Return_DATE_String
                                        + "\n" + PMD_SSOODPR_Ping_Return_TIME_String;



                                    if ((PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                    ("Ping Result:Success") != -1))
                                    {

                                        //Add data to the "Successful Pings" series "SS_Ping_Response" in the chart
                                        //the X values will be the record number and the Y values will be the 
                                        //ping responce that we recived from the device/www/DNS name sites
                                        Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"]
                                            .Points.AddXY(PMD_SSOODPR_X_Axis_Date_and_Time, PMD_SSOODPR_Ping_Return_Time_Integer);

                                        //Add data to the "SS_Ping_Timeout" series in the chart.
                                        //In this case the there will be a value for a successfull ping reponse
                                        //so the "timeout" value will be zero.
                                        //the X values will be the record number and the Y values will be the 
                                        //ping responce that we recived from the device/www/DNS name sites
                                        Snap_Shot_Device_Response_Chart.Series["SS_Ping_Timeout"]
                                            .Points.AddXY(PMD_SSOODPR_X_Axis_Date_and_Time, 0);

                                    }

                                    if ((PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                    ("Ping Result:TimedOut") != -1))
                                    {

                                        //Add data to the "Successful Pings" series "SS_Ping_Response" in the chart.
                                        //In this case the there will be a value for a timed out ping reponse
                                        //so the "suceess" value will be zero value will be zero.
                                        //the X values will be the record number and the Y values will be the 
                                        //ping responce that we recived from the device/www/DNS name sites
                                        Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"]
                                            .Points.AddXY(PMD_SSOODPR_X_Axis_Date_and_Time, 0);

                                        //Add data to the "SS_Ping_Timeout" series in the chart.
                                        //In this case the there will be a value for a successfull ping reponse
                                        //so the "timeout" value will be zero.
                                        //the X values will be the record number and the Y values will be the 
                                        //ping responce that we recived from the device/www/DNS name sites
                                        Snap_Shot_Device_Response_Chart.Series["SS_Ping_Timeout"]
                                            .Points.AddXY(PMD_SSOODPR_X_Axis_Date_and_Time, PMD_SSOODPR_Ping_Return_Time_Integer);

                                    }

                                    
                                }


                            }
                        }


                        if (PMD_TP_Phoenix_Records_In_PingScan_DB >= 99999)
                        {
                            MessageBox.Show("PMD_TP11 - Maximum number of 100000 records reached.  This is temp limit and fixed later");
                        }
                    }
                }

                catch (IOException IFO_ex)
                {
                    //If we can not access or create the file 
                    //and we get an error.  Display the error and
                    //halt the program.
                    String PMD_TP_File_Exist_Message = IFO_ex.Message.ToString();
                    MessageBox.Show("PMD_TS12 - Error openning main inventory data file.  Error - " +
                    PMD_TP_File_Exist_Message);


                    //Exit Phoenix.  We should put in error handling code for the 
                    //exception.  First we will need to figure out what Exceptions
                    //are needed.
                    Application.Exit();
                }

                //MessageBox.Show("Completed Charting");
            
//*****************************************************************************************
//*****************************************************************************************

               
                      

            
            
            //Do the pinged update for the device the user has selected
            //Timed_Update_Of_Devices_Ping_Responses();
            
                
            //Restart the timer
            PMD_Ping_Display_Update_Timer.Enabled = true;

        }

        //==================================================================================
        //==================================================================================
        //This section is code to reset the chart veiw
        

        private delegate void Reset_Chart_View_Statements_Delegate();

        private void Reset_Chart_View_Statements(object sender, RunWorkerCompletedEventArgs e)
        {

            //Reset the chart views
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisX.View.ZoomReset(0);
            Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisY.View.ZoomReset(0);
         
        }
        
        //==================================================================================
        //==================================================================================



        private void Thirty_second_DisplayUpdateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Readjust the title of the chart
            //This next section changes the chart title to 
            //reflect what we are looking at
            Snap_Shot_Device_Response_Chart.Titles[0].Font =
                                     new Font("Times New Roman", 12, FontStyle.Bold);

            //Set the Font color
            Snap_Shot_Device_Response_Chart.Titles[0].Color =
                Color.SteelBlue;

            //Set the Font color
            Snap_Shot_Device_Response_Chart.Titles[0].BackColor =
                Color.Transparent;


            Snap_Shot_Device_Response_Chart.Titles[0].Font =
                new Font("Times New Roman", 12, FontStyle.Bold);

            //Set the Font color
            Snap_Shot_Device_Response_Chart.Titles[0].Color =
                Color.SteelBlue;

            //Set the Font color
            Snap_Shot_Device_Response_Chart.Titles[0].BackColor =
                Color.Transparent;

            Snap_Shot_Device_Response_Chart.Titles[0].Text =
                                    "Timed Update Of Ping Results For "
                                    + PMD_Inventory_List.SelectedNode.Text
                                    +"\n"
                                    +"Interval Timer is Set To 30 Seconds"
                                    + "\n"
                                    + "Report Run Date "
                                    + DateTime.Now.ToLongDateString()
                                    + " "
                                    + DateTime.Now.ToLongTimeString();
            
                       
            //Call the routine that sets the ping update timer to 30 Secounds
            PMD_Ping_Set_Timed_Update_Entire_Data_Set(30000);

            
            MessageBox.Show("PMD_0912090838 - Timer for ping update set to 30 secound interval");
            
        }


        private void Timed_Update_Of_Devices_Ping_Responses()
        {
            //Reset the chart veiw and hide the button
            //Reset the chart Access
            //Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisX.View.ZoomReset(0);
            //Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisY.View.ZoomReset(0);

            //Clear the chart out
            //Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"].Points.Clear();

            //This background thread will clear the chart data for modification
            ThreadPool.QueueUserWorkItem(new WaitCallback(PMD_ThreadProc_Clear_Chart_Data));


            //this is the initial read of the devices data
            //this will set the first right of the graph
            //This will build/rebuild the inventory display list
            //
            //*******************************************************************
            //First check to see if the inventory data file exist
            //We need a flag value to indicate if the file exist
            //or is there is a problem openning it when we try to test 
            //for the main data file in the Phoenix utility.  If the file does
            //not exist it is created.  Either way we must check for problems.
            //this is a boolean value by making the default value "false"
            try
            {
                //Open the file top see if error is generated
                using (FileStream PMD_TUODPR_fs = new FileStream
                    ("\\Phoenix\\PingScans\\Phoenix_PingScans.txt", FileMode.OpenOrCreate))
                {
                    //Guess what.....The file has been either openned 
                    //or created successfully.  Now make sure that it is closed
                    PMD_TUODPR_fs.Close();
                }

            }
            catch (IOException IFO_ex)
            {
                //If we can not access or create the file 
                //and we get an error.  Display the error and
                //halt the program.
                String PMD_TUODPR_File_Exist_Message = IFO_ex.Message.ToString();
                MessageBox.Show("PMD_TUODPR-0912090926 - " +
                    PMD_TUODPR_File_Exist_Message + " It is being created");

                //Try creating the inventory file in case it does not exist
                try
                {
                    //Create the file with the path
                    File.CreateText("\\Phoenix\\PingScans\\Phoenix_PingScans.txt");

                }
                catch (IOException IFO_ex1)
                {
                    //If we can not access or create the file 
                    //and we get an error.  Display the error and
                    //halt the program.
                    String PMD_TUODPR_File_Exist_Message1 = IFO_ex1.Message.ToString();
                    MessageBox.Show("PMD_TUODPR-0912090928 - Error creating main inventory data file.  Error - " +
                    PMD_TUODPR_File_Exist_Message1);
                }


                //Exit Phoenix.  We should put in error handling code for the 
                //exception.  First we will need to figure out what Exceptions
                //are needed.
                Application.Exit();
            }

            //===================================================================================
            //===================================================================================
            //First get the number of records in the data file

            //Open the datafile for a read of all of the existing data
            //so that we can compare what is discovered with what is already
            //in the datafile.

            try
            {
                using (System.IO.StreamReader PMD_TUODPR_Open_Phoenix_PingScan_File =
                        File.OpenText("\\Phoenix\\PingScans\\Phoenix_PingScans.txt"))
                {

                    //set up a variable to read records from 
                    //the Phoenix inventory data file.  I picked a
                    //a number of 10000 as the maximum number of records
                    //that is certainy past the limmit of a small network
                    //string[] PMD_TP_Record_to_Compare = new string[10000];


                    //This section inits the varaible that holds the records
                    //an makes the entire array null
                    for (int PMD_TUODPR_Init_Record_Counter = 0; PMD_TUODPR_Init_Record_Counter < 10000; PMD_TUODPR_Init_Record_Counter++)
                    {
                        //init the slot in the array
                        PMD_TUODPR_Device_to_Scan_For[PMD_TUODPR_Init_Record_Counter] = "";
                    }

                    //Init the counter of the records
                    PMD_TUODPR_Phoenix_Records_In_PingScan_DB = 0;

                    //Start reading the data from the file
                    while ((PMD_TUODPR_Device_Ping_Response_Data[PMD_TUODPR_Phoenix_Records_In_Inventory_DB] =
                        PMD_TUODPR_Open_Phoenix_PingScan_File.ReadLine()) != null)
                    {
                        PMD_TUODPR_Phoenix_Records_In_PingScan_DB = PMD_TUODPR_Phoenix_Records_In_Inventory_DB + 1;
                        if (PMD_TUODPR_Phoenix_Records_In_PingScan_DB >= 9999)
                        {
                            MessageBox.Show("PMD_TUODPR-0912091004 - Maximum number of 10000 records reached.  This is temp limit and fixed later");
                        }
                    }
                }
            }
            catch (IOException IFO_ex)
            {
                //If we can not access or create the file 
                //and we get an error.  Display the error and
                //halt the program.
                String PMD_TUODPR_File_Exist_Message = IFO_ex.Message.ToString();
                MessageBox.Show("PMD_TUOPDR-0912091031 - Error openning main inventory data file.  Error - " +
                PMD_TUODPR_File_Exist_Message);


                //Exit Phoenix.  We should put in error handling code for the 
                //exception.  First we will need to figure out what Exceptions
                //are needed.
                Application.Exit();
            }

            //If there are not any records in the inventory file no
            //sense to process any thing else so exit out of utility
            if (PMD_TUODPR_Phoenix_Records_In_PingScan_DB == 0)
            {

                MessageBox.Show("PMD_TUODPR-0912091038 - Warning - There are no records in the main inventory file to display");

                //exit our of routine
                return;
            }

           
            //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
            //This section will go through the entire database and store only the record
            //that is the IP address selected by the user.

            try
            {
                using (System.IO.StreamReader PMD_TUODPR_Open_Phoenix_PingScan_File =
                        File.OpenText("\\Phoenix\\PingScans\\Phoenix_PingScans.txt"))
                {

                    //public static string[] PMD_TP_Device_Response_Time = new string[100000];
                    //public static int PMD_TP_Phoenix_Number_Of_Response_Time_Records = 0;

                    //set up a variable to read records from 
                    //the Phoenix inventory data file.  I picked a
                    //a number of 10000 as the maximum number of records
                    //that is certainy past the limmit of a small network
                    //string[] PMD_TP_Record_to_Compare = new string[10000];


                    //Init the temp variable that hold the record for processing
                    PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding = "";

                    //This section inits the varaible that holds the records
                    //an makes the entire array null
                    for (int PMD_TUODPR_Init_Record_To_Store_Counter = 0; PMD_TUODPR_Init_Record_To_Store_Counter < 100000; PMD_TUODPR_Init_Record_To_Store_Counter++)
                    {
                        //init the slot in the array
                        PMD_TUODPR_Device_Response_Time[PMD_TUODPR_Init_Record_To_Store_Counter] = "";
                    }

                    //Init the counter of the records
                    PMD_TUODPR_Phoenix_Records_In_PingScan_DB = 0;

                    //init the value that stores the counter for number of 
                    //datapoints on the graph
                    int PMD_TUODPR_number_of_xseries_DP = 0;

                    //Start reading the data from the file
                    while ((PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding =
                        PMD_TUODPR_Open_Phoenix_PingScan_File.ReadLine()) != null)
                    {
                        PMD_TUODPR_Phoenix_Records_In_PingScan_DB = PMD_TP_Phoenix_Records_In_Inventory_DB + 1;

                        //Next see if this record contains the IP address that the 
                        //user has selected.
                        //init the vairable that would contain a value greater than
                        //-1 if we found the text the user has selected
                        int PMD_TUODPR_Index = 0;

                        //check for the IP address the user selected
                        
                            //PMD_TUODPR_Index = PMD_TP_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                //(PMD_Inventory_List.SelectedNode.Text);
                        PMD_TUODPR_Index = PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                   (PMD_TUODPR_Single_Selected_Node);
                            //PMD_TUODPR_Index = PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                            //(PMD_TUODPR_Single_Selected_Node_Passed);
                        
                        if (PMD_TUODPR_Index == -1 || PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                            (",", (PMD_TUODPR_Index + PMD_TUODPR_Single_Selected_Node.Length), 1) == -1)
                       
                            //if (PMD_TUODPR_Index == -1 || PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                            //(",", (PMD_TUODPR_Index + PMD_Inventory_List.SelectedNode.Text.Length), 1) == -1)
                        {
                            //MessageBox.Show("NO HIT");
                        }
                        else
                        {
                            //If we get to this point we have found the record in the 
                            //inventory file that we need.  Now we must extract the 
                            //if the ping was successfull.  If we find the phase Ping Result:Success or 
                            //the phase Ping Result:TimedOut for the times we we can not find the Success
                            //in the record then record the time
                            int PMD_TUODPR_Index_Ping_Result = 0;
                            PMD_TUODPR_Index_Ping_Result = PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                            ("Ping Result:Success");

                            if ((PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                ("Ping Result:Success") != -1) ^ (PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                ("Ping Result:TimedOut") != -1))
                            {
                                //Find the value for the repsonse time of the ping
                                //Get the value by finding the phrase "Ping Return Time: 
                                //Step one: Find where the ping return data is in the 
                                //record
                                int PMD_TUODPR_Ping_Response_In_Record = 0;
                                PMD_TUODPR_Ping_Response_In_Record =
                                    PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf("Ping Return Time:") + 1;

                                //Find the location of the first comma "," after the ping return time
                                int PMD_TUODPR_Comma_After_Ping_Return_Time = 0;
                                PMD_TUODPR_Comma_After_Ping_Return_Time =
                                    PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                    (",", PMD_TUODPR_Ping_Response_In_Record);

                                //Note that we must determine the number of digits that the 
                                //return time is.  This is done by taking the location of the comma
                                //after the return time and subtracting the starting location of
                                //"Ping Return Time Text" plus 7 which equals the location just
                                //before the start of the Ping Return digits.
                                //There may be a better way to do this but this seems good for now.
                                int PMD_TUODPR_Comma_After_Ping_Return_Time_Length = 0;
                                PMD_TUODPR_Comma_After_Ping_Return_Time_Length =
                                    ((PMD_TUODPR_Comma_After_Ping_Return_Time) -
                                    (PMD_TUODPR_Ping_Response_In_Record + 16));

                                //Parse the record and store the string in a variable
                                string PMD_TUODPR_Ping_Return_Time_String = "";
                                PMD_TUODPR_Ping_Return_Time_String =
                                    PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.Substring
                                    (PMD_TUODPR_Ping_Response_In_Record + 16, PMD_TUODPR_Comma_After_Ping_Return_Time_Length);

                                //Next convert the string value to an integer
                                int PMD_TUODPR_Ping_Return_Time_Integer = 0;
                                PMD_TUODPR_Ping_Return_Time_Integer =
                                    Convert.ToInt32(PMD_TUODPR_Ping_Return_Time_String);

                                //indcrement the counter that holds the number of data points
                                //in the graph
                                PMD_TUODPR_number_of_xseries_DP =
                                    PMD_TUODPR_number_of_xseries_DP + 1;


                           
                                //The charts are constructed in anoother thread as such they must be access that way
                                //The thread pool does this
                                //Commented out 12/05/09 14:08
                                //ThreadPool.QueueUserWorkItem(new WaitCallback(Chart_Title_ThreadProc));
                                                             
                                //***************************************************************************
                                //The ThreadPool statement above replaces the commented out lines between
                                //the "*"
                                //This next section changes the chart title to 
                                //reflect what we are looking at
                                //Snap_Shot_Device_Response_Chart.Titles[0].Font =
                                //    new Font("Times New Roman", 12, FontStyle.Bold);
                                //
                                //Set the Font color
                                //Snap_Shot_Device_Response_Chart.Titles[0].Color =
                                //    Color.SteelBlue;
                                //
                                //Set the Font color
                                //Snap_Shot_Device_Response_Chart.Titles[0].BackColor =
                                //    Color.Transparent;


                                
                                //Change the chart title to reflect the Snap shot optione
                                //and IP address we are looking at.
                                //Snap_Shot_Device_Response_Chart.Titles[0].Text =
                                //    "Timed Update Of Ping Results For "
                                //    + PMD_Inventory_List.SelectedNode.Text
                                //    + "\n"
                                //    + "Update Interval Is "
                                //    + PMD_Ping_Display_Update_Timer.ToString()
                                //    +"\n"
                                //    + "Report Run Date/Time "
                                //    + DateTime.Now.ToLongDateString()
                                //    +DateTime.Now.ToLongTimeString();



                                //Find the value for the date of the ping
                                //Get the value by finding the phrase "DATE: 
                                //Step one: Find where the ping return DATE is in the 
                                //record
                                int PMD_TUODPR_Ping_DATE_In_Record = 0;
                                PMD_TUODPR_Ping_DATE_In_Record =
                                    PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf("DATE:");

                                //Find the location of the first comma "," after the ping return time
                                int PMD_TUODPR_Comma_After_Ping_Return_DATE = 0;
                                PMD_TUODPR_Comma_After_Ping_Return_DATE =
                                    PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                    (",", PMD_TUODPR_Ping_DATE_In_Record);

                                //Note that we must determine the number of digits that the 
                                //ping DATE is.  This is done by taking the location of the comma
                                //after the ping DATE and subtracting the starting location of
                                //"Ping DATE Text" plus 5 which equals the location just
                                //before the start of the Ping DATE digits.
                                //There may be a better way to do this but this seems good for now.
                                int PMD_TUODPR_Comma_After_Ping_DATE_Length = 0;
                                PMD_TUODPR_Comma_After_Ping_DATE_Length =
                                    ((PMD_TUODPR_Comma_After_Ping_Return_DATE) -
                                    (PMD_TUODPR_Ping_DATE_In_Record + 5));

                                //Parse the record and store the string in a variable
                                string PMD_TUODPR_Ping_Return_DATE_String = "";
                                PMD_TUODPR_Ping_Return_DATE_String =
                                    PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.Substring
                                    ((PMD_TUODPR_Ping_DATE_In_Record + 5), PMD_TUODPR_Comma_After_Ping_DATE_Length);


                                //Find the value for the TIME of the ping
                                //Get the value by finding the phrase "TIME: 
                                //Step one: Find where the ping return TIME is in the 
                                //record
                                int PMD_TUODPR_Ping_TIME_In_Record = 0;
                                PMD_TUODPR_Ping_TIME_In_Record =
                                    PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf("TIME:");

                                //Find the location of the first comma "," after the ping return time
                                int PMD_TUODPR_Comma_After_Ping_Return_TIME = 0;
                                PMD_TUODPR_Comma_After_Ping_Return_TIME =
                                    PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                    (",", PMD_TUODPR_Ping_TIME_In_Record);

                                //Note that we must determine the number of digits that the 
                                //ping TIME is.  This is done by taking the location of the comma
                                //after the ping TIME and subtracting the starting location of
                                //"Ping TIME Text" plus 5 which equals the location just
                                //before the start of the Ping TIME digits.
                                //There may be a better way to do this but this seems good for now.
                                int PMD_TUODPR_Comma_After_Ping_TIME_Length = 0;
                                PMD_TUODPR_Comma_After_Ping_TIME_Length =
                                    ((PMD_TUODPR_Comma_After_Ping_Return_TIME) -
                                    (PMD_TUODPR_Ping_TIME_In_Record + 5));

                                //Parse the record and store the string in a variable
                                string PMD_TUODPR_Ping_Return_TIME_String = "";
                                PMD_TUODPR_Ping_Return_TIME_String =
                                    PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.Substring
                                    ((PMD_TUODPR_Ping_TIME_In_Record + 5), PMD_TUODPR_Comma_After_Ping_TIME_Length);

                                //This section does the date extract from the record and
                                //formats it for the chart
                                //This is a test to see if we can get the date and time in to the
                                //chart X-Axis.
                                string PMD_TUODPR_X_Axis_Date_and_Time = "";
                                PMD_TUODPR_X_Axis_Date_and_Time = PMD_TUODPR_Ping_Return_DATE_String
                                    + "\n" + PMD_TUODPR_Ping_Return_TIME_String;



                                if ((PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                ("Ping Result:Success") != -1))
                                {

                                    //Add data to the "Successful Pings" series "SS_Ping_Response" in the chart
                                    //the X values will be the record number and the Y values will be the 
                                    //ping responce that we recived from the device/www/DNS name sites
                                    Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"]
                                        .Points.AddXY(PMD_TUODPR_X_Axis_Date_and_Time, PMD_TUODPR_Ping_Return_Time_Integer);

                                    //Add data to the "SS_Ping_Timeout" series in the chart.
                                    //In this case the there will be a value for a successfull ping reponse
                                    //so the "timeout" value will be zero.
                                    //the X values will be the record number and the Y values will be the 
                                    //ping responce that we recived from the device/www/DNS name sites
                                    Snap_Shot_Device_Response_Chart.Series["SS_Ping_Timeout"]
                                        .Points.AddXY(PMD_TUODPR_X_Axis_Date_and_Time, 0);

                                }

                                if ((PMD_TUODPR_Device_Ping_Response_Data_Temp_Holding.IndexOf
                                ("Ping Result:TimedOut") != -1))
                                {

                                    //Add data to the "Successful Pings" series "SS_Ping_Response" in the chart.
                                    //In this case the there will be a value for a timed out ping reponse
                                    //so the "suceess" value will be zero value will be zero.
                                    //the X values will be the record number and the Y values will be the 
                                    //ping responce that we recived from the device/www/DNS name sites
                                    Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"]
                                        .Points.AddXY(PMD_TUODPR_X_Axis_Date_and_Time, 0);

                                    //Add data to the "SS_Ping_Timeout" series in the chart.
                                    //In this case the there will be a value for a successfull ping reponse
                                    //so the "timeout" value will be zero.
                                    //the X values will be the record number and the Y values will be the 
                                    //ping responce that we recived from the device/www/DNS name sites
                                    Snap_Shot_Device_Response_Chart.Series["SS_Ping_Timeout"]
                                        .Points.AddXY(PMD_TUODPR_X_Axis_Date_and_Time, PMD_TUODPR_Ping_Return_Time_Integer);

                                }

                                
                                //Reset the chart view via it's own thread
                                //12/05/09 commented out
                                //ThreadPool.QueueUserWorkItem(new WaitCallback(Chart_View_Reset_ThreadProc));

                                //**************************************************************************
                                //The lines below have been commented out because the ThreadPool above takes
                                //care of the reset of the veiw
                                //Reset the chart Access
                                //Snap_Shot_Device_Response_Chart.ResetAutoValues();

                                //Reset the chart Access
                                //Snap_Shot_Device_Response_Chart.Visible = true;
                                //Snap_Shot_Device_Response_Chart.Enabled = true;
                                //Make the chart reset button visible
                                //PMD_Chart_Reset_Button.Visible = true;
                                //*****************************************************************************




                            }










                        }
                    }


                    if (PMD_TP_Phoenix_Records_In_PingScan_DB >= 99999)
                    {
                        MessageBox.Show("PMD_TP11 - Maximum number of 100000 records reached.  This is temp limit and fixed later");
                    }
                }
            }

            catch (IOException IFO_ex)
            {
                //If we can not access or create the file 
                //and we get an error.  Display the error and
                //halt the program.
                String PMD_TP_File_Exist_Message = IFO_ex.Message.ToString();
                MessageBox.Show("PMD_TS12 - Error openning main inventory data file.  Error - " +
                PMD_TP_File_Exist_Message);


                //Exit Phoenix.  We should put in error handling code for the 
                //exception.  First we will need to figure out what Exceptions
                //are needed.
                Application.Exit();
            }

            MessageBox.Show("Completed Charting");



        }

       private void dynamicUpdateForHighlightedItemToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

       private delegate void Delegate_Chart_Update_Interval_Title();
        
       private void Ping_Charts_Interval_Update_Title()
       {

           //This next section changes the chart title to 
           //reflect what we are looking at
           Snap_Shot_Device_Response_Chart.Titles[0].Font =
                                    new Font("Times New Roman", 12, FontStyle.Bold);

           //Set the Font color
           Snap_Shot_Device_Response_Chart.Titles[0].Color =
               Color.SteelBlue;

           //Set the Font color
           Snap_Shot_Device_Response_Chart.Titles[0].BackColor =
               Color.Transparent;
                     
           
           Snap_Shot_Device_Response_Chart.Titles[0].Font =
               new Font("Times New Roman", 12, FontStyle.Bold);

           //Set the Font color
           Snap_Shot_Device_Response_Chart.Titles[0].Color =
               Color.SteelBlue;

           //Set the Font color
           Snap_Shot_Device_Response_Chart.Titles[0].BackColor =
               Color.Transparent;

           //Change the chart title to reflect the Snap shot optione
           //and IP address we are looking at.
           Snap_Shot_Device_Response_Chart.Titles[0].Text =
               "Timed Update Of Ping Results For "
               + PMD_Inventory_List.SelectedNode.Text
               + "\n"
               + "Update Interval Is "
               //Wnat to display in seconds so divide by 1000 to get there
               + (PMD_Ping_Expire_Time_Global/1000).ToString()
               + "\n"
               + "Report Run Date/Time "
               + DateTime.Now.ToLongDateString()
               + DateTime.Now.ToLongTimeString();
           
       }
        //Commented out 12/05/09 14:11
       //private void Chart_Title_ThreadProc(object stateInfo)
       //{
           ////Update the Chart
           //Delegate_Chart_Update_Interval_Title DCUIT = new Delegate_Chart_Update_Interval_Title(Ping_Charts_Interval_Update_Title);
           //BeginInvoke(DCUIT, null);
                     
       //}


       //Commented out 12/05/09 14:12
       //private void Chart_View_Reset_ThreadProc(object stateInfo1)
       //{
           //Delegate_for_Chart_View_Reset DFCVR = new Delegate_for_Chart_View_Reset(Reset_Ping_Chart_Veiw);
           //BeginInvoke(DFCVR, null);

       //}

       //Commented out 12/05/09 14:13
       //private delegate void Delegate_for_Chart_View_Reset();
       private void Reset_Ping_Chart_Veiw()
       {
           //Reset the chart Access
           Snap_Shot_Device_Response_Chart.ResetAutoValues();

           //Reset the chart Access
           Snap_Shot_Device_Response_Chart.Visible = true;
           Snap_Shot_Device_Response_Chart.Enabled = true;
           //Make the chart reset button visible
           PMD_Chart_Reset_Button.Visible = true;

       }
        private void PMD_ThreadProc_Clear_Chart_Data(object stateinfo)
        {
            //Develop the thread that will be used to init the chart dataset.
            PMD_Chart_Reset_Button_Delegate PMD_DLG = new PMD_Chart_Reset_Button_Delegate(PDM_Clear_Chart_Data);
            this.BeginInvoke(PMD_DLG, null);
                   
        }
               
        private delegate void PMD_Chart_Reset_Button_Delegate();
        private void PDM_Clear_Chart_Data()
       {
           //Reset the chart veiw and hide the button
           //Reset the chart Access
           //Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisX.View.ZoomReset(0);
           //Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisY.View.ZoomReset(0);

           //Clear the chart out
           Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"].Points.Clear();
           
           MessageBox.Show("Cleared Points on Chart");
       }


        //**********************************************************************************************
        //**********************************************************************************************
        //This setion will store the data in the array via a cross thread operation
        

        //private void PMD_Store_Data_In_The_Array_Successful_Ping_ThreadProc
            //(object StateInfo, String PMD_TUODPR_X_Axis_Date_and_Time_Delegate10,int PMD_TUODPR_Ping_Return_Time_Integer_Delegate10)
        //{
            ////Sent to Expert exchange 12/06/09 12:00
            //PMD_Store_The_Successful_Ping_Data PMD_Successful_Ping = new PMD_Store_The_Successful_Ping_Data(PMD_Store_Data_In_The_Array_Successful_Ping(PMD_TUODPR_X_Axis_Date_and_Time_Delegate10,PMD_TUODPR_Ping_Return_Time_Integer_Delegate10));

            //this.Invoke(PMD_Successful_Ping, new object[] { PMD_TUODPR_X_Axis_Date_and_Time_Delegate10, PMD_TUODPR_Ping_Return_Time_Integer_Delegate10 }); 
        
        //}
                
        //Set up the private delgate and the routine that does all of the work
        //private delegate void PMD_Store_The_Successful_Ping_Data(String PMD_TUODPR_X_Axis_Date_and_Time_Delegate0, int PMD_TUODPR_Ping_Return_Time_Integer_Delegate0);
       

        
        private void PMD_Store_Data_In_The_Array_Successful_Ping(String PMD_TUODPR_X_Axis_Date_and_Time_Delegate1, int PMD_TUODPR_Ping_Return_Time_Integer_Delegate1)
        {
            //Store the data that was passed
            //Add data to the "Successful Pings" series "SS_Ping_Response" in the chart
            //the X values will be the record number and the Y values will be the 
            //ping responce that we recived from the device/www/DNS name sites
            Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"]
                .Points.AddXY(PMD_TUODPR_X_Axis_Date_and_Time_Delegate1, PMD_TUODPR_Ping_Return_Time_Integer_Delegate1);

            //Add data to the "SS_Ping_Timeout" series in the chart.
            //In this case the there will be a value for a successfull ping reponse
            //so the "timeout" value will be zero.
            //the X values will be the record number and the Y values will be the 
            //ping responce that we recived from the device/www/DNS name sites
            Snap_Shot_Device_Response_Chart.Series["SS_Ping_Timeout"]
                .Points.AddXY(PMD_TUODPR_X_Axis_Date_and_Time_Delegate1, 0);

        }

        private void PMD_Store_Data_In_The_Array_TimeOut_Ping(String PMD_TUODPR_X_Axis_Date_and_Time_Delegate2, int PMD_TUODPR_Ping_Return_Time_Integer_Delegate2)
        {
            //Store the data that was passed
            //Add data to the "Successful Pings" series "SS_Ping_Response" in the chart
            //the X values will be the record number and the Y values will be the 
            //ping responce that we recived from the device/www/DNS name sites
            Snap_Shot_Device_Response_Chart.Series["SS_Ping_Response"]
                .Points.AddXY(PMD_TUODPR_X_Axis_Date_and_Time_Delegate2, 0);

            //Add data to the "SS_Ping_Timeout" series in the chart.
            //In this case the there will be a value for a successfull ping reponse
            //so the "timeout" value will be zero.
            //the X values will be the record number and the Y values will be the 
            //ping responce that we recived from the device/www/DNS name sites
            Snap_Shot_Device_Response_Chart.Series["SS_Ping_Timeout"]
                .Points.AddXY(PMD_TUODPR_X_Axis_Date_and_Time_Delegate2, PMD_TUODPR_Ping_Return_Time_Integer_Delegate2);

        }

        //###################################################################################################
        //###################################################################################################
        //Added per expert exchange 12/30/09 12:50pm
        void SetText(string Text)
        {
            // When called by the background worker, InvokeRequired will be true
            if (this.Snap_Shot_Device_Response_Chart.InvokeRequired)
            {
                // "d" is now a variable, but instead of a variable that
                // points to/contains an object or string or something,
                // it points to a function - the function it points to
                // is SetText, which is *this* function
                SetTextDelegate d = new SetTextDelegate(SetText);

                // This line calls this forms .Invoke method, which will
                // execute the function pointed to by "d" (which is *this* function)
                // on the same thread the form and text box were created on
                // The "first" time through this function, when called by
                // background thread, we're just going to use this .Invoke
                // method to re-run this same method, but on the form's thread
                this.Invoke(d, new object[] { Text });
            }
            else
            {
                // The "second" time through this function will be the result
                // of the .Invoke, which means we'll be on the same thread as 
                // the form, so the textBox1.InvokeRequired above will return
                // false, and since we're on the same thread as the form and
                // text box we can directly set the .Text property.
                //this.textBox1.Text = Text;
                this.Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisX.View.ZoomReset(0);
                this.Snap_Shot_Device_Response_Chart.ChartAreas["Default"].AxisY.View.ZoomReset(0);
            }
        }
        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // RunWorkerCompleted runs on same thread the
            // background worker was created on, which
            // is this form, so can set .Text directly
            //textBox1.Text = "Worker Completed";
            //Change the chart title to reflect the Snap shot optione
            //and IP address we are looking at.
            Snap_Shot_Device_Response_Chart.Titles[0].Text =
                "RWCE - Timed Update Of Ping Results For "
                + PMD_Inventory_List.SelectedNode.Text
                + "\n"
                + "Update Interval Is "
                //Wnat to display in seconds so divide by 1000 to get there
                + (PMD_Ping_Expire_Time_Global / 1000).ToString()
                + "\n"
                + "Report Run Date/Time "
                + DateTime.Now.ToLongDateString()
                + DateTime.Now.ToLongTimeString();
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            // DoWork event runs on background thread
            // so this delegate/invoke work around is necessary
            SetText("Worker Started");
            System.Threading.Thread.Sleep(5000);
        }

        private void button1_ClickA(object sender, EventArgs e)
        {
            worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            worker.RunWorkerAsync();
        }
        //#########################################################################################################
        //#########################################################################################################
        







    }
}

Open in new window

Code-Collection-Modified-Error-1.png
If you click "View Detail" on that exception message box may shed some light on which line of code is actually causing you the problem, or stepping through your code one line at a time. The debugger has stopped on this line because there's something in the constructor for your form that is the source of grief, it's not really this line that's the problem though.

This message occurs when you attempt to modify a collection while using a "for" or "foreach" loop on that collection.  For example,
ArrayList theList = new ArrayList();

theList.Add("One");
theList.Add("Two");
theList.Add("Three");

foreach (string listItem in theList)
{
      if (listItem == "Two")
            theList.Remove("Two"); // Causes exception because it attempts to modify theList while we're enumerating theList in a foreach
}
I was able to duplicate the origination and step through the code the was having the problem.  It is somehow still related to the thread writing to the UI.  I managed to record the session that contains myself stepping through each of the statements in showing exactly where the exception occurs.

Any thoughts would be appreciated........

Thanks,
George
P.S. Please note that  you have to change to extension on the file to AVI from PNG
Recording-of-Exception-123009154.png
ASKER CERTIFIED SOLUTION
Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
tgerbert,

Great job!!! Based on your suggestions I was able to discover the answer.  Thanks you for your kind suggestions.

George