I have a TreeView control, which is populated with items (one for every file in a specific directory), and a Thread which runs in the background, which slowly populates each node in the tree with extra data.
I then need the TreeViewNode to update its Text field, based on the results.
I've tried using BeginInvoke on the worker for each item, after its been processed, but this causes the GUI thread to become unresponsive, due to the shear number of nodes that the background worker is processing. C# - Updating GUI using non-main Thread
public static void InvokeIfRequired(this System.Windows.Forms.Control c,
Action action) {
if (c.InvokeRequired) {
c.Invoke((Action)(() => action()));
}
else {
action();
}
}
I've tried batching up several node updates into a single work item for the GUI, and using BeginInvoke to update several at once, during which the background thread waits on a signal to continue its work, but this also causes the GUI to become unresponsive during the Invoked method (seems like updating TreeViewNode is quite an expensive operation?)
Lastly, I created a queue on the GUI thread, which is populated by the worker thread, and is polled when the Application is idle, which works nicely, but feels like a complete hack.
using System;
using System.Runtime.InteropServices;
namespace System
{
struct PointAPI
{
public Int32 x;
public Int32 y;
}
struct WindowsMessage
{
public Int32 hwnd;
public Int32 message;
public Int32 wParam;
public Int32 lParam;
public Int32 time;
public PointAPI pt;
}
static class IdlePolling
{
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PeekMessage(ref WindowsMessage lpMsg,
Int32 hwnd,
Int32 wMsgFilterMin,
Int32 wMsgFilterMax,
Int32 wRemoveMsg);
static public bool HasEventsPending()
{
WindowsMessage msg = new WindowsMessage();
return PeekMessage(ref msg, 0, 0, 0, 0);
}
}
}
...
Application.Idle += mainForm.OnIdle;
...
public partial class MainWindow : Form
{
...
public void OnIdle(object sender, EventArgs e)
{
while (IdlePolling.HasEventsPending() == false)
{
ConsumeGUIUpdateItem();
Thread.Sleep(50);
}
}
}
So what is the "correct" way of updating lots of gui items, which won't cause the GUI thread to hang in the process.