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?
CodePudding user response:
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;
}));
}