У меня есть элемент управления TreeView, который заполняется элементами (по одному для каждого файла в определенном каталоге), и поток, работающий в фоновом режиме, который медленно заполняет каждый узел в дереве дополнительными данными.
Затем мне нужно TreeViewNode, чтобы обновить его текстовое поле на основе результатов.
Я пытался использовать BeginInvoke на рабочем для каждого элемента после его обработки, но это приводит к тому, что поток GUI перестает отвечать на запросы из-за количества узлов, которое обрабатывает фоновый работник.
C # - Обновление графического интерфейса с использованием неосновной темы
public static void InvokeIfRequired(this System.Windows.Forms.Control c,
Action action) {
if (c.InvokeRequired) {
c.Invoke((Action)(() => action()));
}
else {
action();
}
}
Я попытался объединить несколько обновлений узла в один рабочий элемент для графического интерфейса и использовать BeginInvoke для одновременного обновления нескольких элементов, во время которого фоновый поток ожидает сигнала для продолжения своей работы, но это также вызывает графический интерфейс перестать отвечать на запросы во время вызова метода (кажется, что обновление TreeViewNode - довольно дорогая операция?)
Наконец, я создал очередь в потоке графического интерфейса, который заполняется рабочим потоком и опрашивается, когда приложение находится в режиме ожидания, что хорошо работает, но похоже на полный взлом.
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);
}
}
}
Итак, каков «правильный» способ обновления большого количества элементов графического интерфейса, который не приведет к зависанию потока GUI в процессе.