Отображение вкладки с большим количеством элементов управления ComboBox происходит медленно с WinForms

Я создал диалог с несколькими вкладками. Один из них содержит двадцать полей со списком, каждое с более чем 100 элементами, добавленными следующим образом:

foreach (var x in collection)
{
    string text = FormatItem (x);
    combo.Items.Add (text);
}

так что в предметах нет ничего особенного. Это простые строки, и поля со списком заполняются при создании диалога. Это происходит почти мгновенно.

Однако, когда пользователь щелкает вкладку, содержащую все эти поля со списком в первый раз, графический интерфейс зависает на несколько секунд (а я работаю на действительно мощной машине).

Я загрузил символы для System.Windows.Forms и попытался взломать отладчик, пока программа зависла. Я обнаружил трассировку стека со следующими вызовами:

System.Windows.Forms.Control.CreateHandle()
System.Windows.Forms.ComboBox.CreateHandle()
System.Windows.Forms.Control.CreateControl(...) x 3
System.Windows.Forms.Control.SetVisibleCore(true)
System.Windows.Forms.TabPage.Visible.set(true)

что приводит к множеству собственных переходов, WndProc вызовов и т. д. Я полагаю, что это происходит для каждого отдельного элемента в каждом поле со списком. Уф.

Очевидно, я не могу оптимизировать WinForms. Но, может быть, я смогу предпринять какие-то действия, чтобы не потерять весь этот ад из-за моего плохого графического интерфейса? Любые идеи?

Nota Bene:

  1. У меня нет обработчиков событий, прикрепленных к полям со списком, которые можно было бы вызывать, когда элементы управления создаются по-настоящему.

  2. Если я пытаюсь получить доступ к Handleсвойству полей со списком сразу после создания и заполнения формы, я оплачиваю штраф в тот момент, а не тогда, когда вкладка становится видимой в первый раз. Но ждать несколько секунд при создании формы тоже недопустимо. Я действительно хочу избавиться от долгого времени на настройку.

  3. Идея применения BeginUpdateи EndUpdateздесь неприменима: их следует использовать для предотвращения перерисовки элемента управления при заполнении его списка элементов. Но в моем случае проблема возникает уже после настройки управления.

Ответов (5)

Решение

Все, что я пробовал до сих пор, не помогло ускорить первое отображение вкладки, содержащей все поля со списком. Связывание данных тоже не помогло.

В конце концов я решил исправить проблему, выполнив трюк, аналогичный тому, что предлагал Дэнбистром , то есть заполнять Items коллекцию только тогда, когда фокус впервые попадает в комбо. Это по-прежнему вызывает заметную задержку времени создания всех элементов (в пределах одной BeginUpdate и EndUpdate пары вызовов методов), но это терпимо (примерно 200 мс против нескольких секунд в моем исходном сценарии).

Я только что столкнулся с той же проблемой, когда заполнение поля со списком примерно 4000 тыс. Элементов было неприемлемо медленным.

Я заполнял комбо в обработчике события OnLoad формы, однако, когда я перенес этот код в конструктор, после InitializeComponent () задержки вообще не было.

Я предполагаю, что выполнение этой операции в OnLoad приводило к срабатыванию перерисовки комбо, отсюда и задержка? В любом случае, просто подумал, что добавлю это на случай, если это будет полезно кому-то еще в этой ситуации.

То, что вы говорите, не согласуется с тем, что я когда-либо наблюдал ...: s

Но пробовали ли вы использовать .BeginUpdate / .EndUpdate?

Еще одна вещь, которую вы можете попробовать, - это не заполнять коробки до тех пор, пока она не понадобится. Например, отложите это до тех пор, пока поле не получит фокус ... (Если вы перехватите событие раскрывающегося списка, некоторый пользователь может быть раздражен тем, что клавиши со стрелками вверх / вниз не будут работать.)

Вместо итерации ваших коллекций не будет ли установка ComboBox.DataSource жизнеспособной и гораздо более быстрой альтернативой?

comboBox1.DataSource = myCollection1;
comboBox2.DataSource = myCollection2;
comboBox3.DataSource = myCollection3;
// and so on...

Вот более полный пример:

public class Entity
    {
        public string Title { get; set; }
        public override string ToString()
        {
            return Title;
        }
    }
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            List<Entity> list = new List<Entity>
                                    {
                                        new Entity {Title = "Item1"},
                                        new Entity {Title = "Item2"},
                                        new Entity {Title = "Item3"}
                                    };

            comboBox1.DataSource = list;

        }

Проблемой может быть множество элементов управления в форме. Однажды у меня была форма, которая динамически создавалась между 50-100 элементами управления текстовым полем. Загрузка была медленной.

Мы решили эту проблему, используя вместо этого сетку данных. Это элемент управления, оптимизированный для большого количества данных. Я не знаю, каковы ваши точные требования, но это может сработать.