2

I have a TreeView in-which some of the nodes have a tag property that contains an IP address.

The TreeView has an ImageList that contains 3 entries, a red circle, a green circle and an orange circle.

I want to ping the appropriate IP address every x seconds (I currently have a timer that send a 'pulse' every minute) and then update the ImageIndex of the associated Node to represent the correct output (failed = red, etc).

What I am stuck on is updating the UI thread during this operation, I'm sure that the Timer works asynchronously and so it won't be on the same thread as the UI.

I assumed that calling a method that isn't asynchronous would allow me to update the UI however I'm getting an error that I am on the wrong thread to edit the UI.

Here's my method that runs on the Timer's thread, which iterates through each list and sends a ping request to each IP.

private void OnTimedEvent(Object source, ElapsedEventArgs e)
{
    // Iterate through all root nodes
    foreach(TreeNode tn in mainTree.Nodes)
    {
        // Iterate through all the children of the 'root' nodes
        foreach(TreeNode child in tn.Nodes)
        {
            // Extract all nodes from these children
            TreeNodeCollection myNodes = ((TreeNode)child).Nodes;

            // Create ping object
            System.Net.NetworkInformation.Ping pinger = new();
            PingReply pingReply;

            // Iterate through each of the nodes, send a ping request and then update the UI based on the result of the ping
            foreach(TreeNode node in myNodes)
            {
                if(node.Tag != null)
                {
                    pingReply = pinger.Send(node.Tag.ToString());

                    if (pingReply.Status.ToString().Contains("Success"))
                    {
                        UpdateUI(node, 0); // If successful, set the image index to show green 
                    } 
                    else if (pingReply.Status.ToString().Contains("Failed"))
                    {
                        UpdateUI(node, 1);
                    }
                }
            }
        }
             
    }
}

How I'm trying to update the UI:

public static void UpdateUI(TreeNode node, int image) // int image = the index of the image 0 = green, 1 = red, 2 = orange for UI elements
{
    node.ImageIndex = image;
}

The Timer:

private void StartTimer()
{
    aTimer = new System.Timers.Timer(60000); // Set interval to every minute
    aTimer.Elapsed += OnTimedEvent;
    aTimer.AutoReset = true;
    aTimer.Enabled = true;
}

Initialising the timer:

public Form1()
{
    InitializeComponent();

    StartTimer();

    // Instantiate TreeViewSerializer class for persistence
    TreeViewSerializer tvS = new TreeViewSerializer();
    // Deserealize tree view for persistence
    tvS.DeserializeTreeView(mainTree, xmlFile);
    mainTree.ImageList = imageList1;
    mainTree.ExpandAll();
}

How do I access the UI thread in order to be able to update the UI using the values returned from a successful/failed ping?

Thomton
  • 102
  • 13
  • 1
    [Timer.SynchronizingObject](https://learn.microsoft.com/en-us/dotnet/api/system.timers.timer.synchronizingobject?view=net-7.0) – dr.null Oct 05 '22 at 16:49
  • Any reason to not use the `System.Windows.Forms.Timer` ? Also, the `Ping` class provides `Async` methods so you can adopt the `async/await` pattern in async context. – dr.null Oct 05 '22 at 17:12
  • @dr.null I was having a problem with `Forms.Timer` not firing the 'tick' events properly. – Thomton Oct 06 '22 at 10:04

1 Answers1

1

Try to change your method:

public static void UpdateUI(TreeNode node, int image) // int image = the index of the image 0 = green, 1 = red, 2 = orange for UI elements
{
    node.ImageIndex = image;
}

to:

public static void UpdateUI(TreeNode node, int image) // int image = the index of the image 0 = green, 1 = red, 2 = orange for UI elements
{
    this.Invoke(new Action(() =>
    {
       node.ImageIndex = image;
    }));
}
TonyMkenu
  • 7,597
  • 3
  • 27
  • 49
  • To add to the above just-fine answer: NET Framework: See a nice discussion with multiple approaches at https://stackoverflow.com/questions/661561/how-do-i-update-the-gui-from-another-thread. UWP: See https://stackoverflow.com/questions/38149767/uwp-update-ui-from-task. Xamarin: See https://stackoverflow.com/questions/45195232/updating-the-ui-with-xamarin. What do all of these have in common? They are all on stack overflow. – user1318024 Oct 05 '22 at 16:53