Обновление списка c # без «задержки» - PullRequest
0 голосов
/ 05 февраля 2012

Я искал в Интернете способ сделать это без особого успеха, поэтому вот вопрос.

Как добавить элементы в список в отдельном потоке, чтобы он не зависал? Каждый раз в списки добавляется примерно 5-15 тысяч элементов, и пользователь каждый раз останавливает интерфейс на 5-12 секунд.

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

например.

for (int n = 0; n < 7500; n++)
{
    listBox1.Items.Add(itemList[n, 0].ToString());
    listBox2.Items.Add(itemList[n, 1].ToString());
    listBox3.Items.Add(itemList[n, 2].ToString());
    listBox4.Items.Add(itemList[n, 3].ToString());
}

Как указано выше, как использовать поток, отличный от пользовательского интерфейса, для обновления этих списков, чтобы предотвратить ненужное зависание пользовательского интерфейса

Ответы [ 7 ]

4 голосов
/ 06 февраля 2012

Вы можете использовать другой подход и использовать вместо него виртуальный ListView.Когда ListView является «виртуальным», вы несете ответственность за ведение списков элементов и указание ListView, что отображать в событиях рисования.Таким образом, вы можете обновлять свои списки любым потокобезопасным способом, который вам нравится, и ListView будет спрашивать вас только «что рисовать на экране», а не полный список элементов.Это на самом деле предпочтительный метод, когда получение списка всех элементов очень дорого.

См. Документацию по VirtualMode:

http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.virtualmode.aspx

ОБНОВЛЕНИЕ: Поскольку вы упомянули, что вам нужнодля отладки я также предлагаю вам использовать выходные данные отладки (Debug.WriteLine()), которые могут быть более подходящими для работы.Он оптимизирован, он безопасен для потоков, он не блокирует ничего, кроме себя, и, что самое приятное, он не влияет на производительность сборок релиза.

И в случае, если вам нужен более производительный вывод, вы можете перенаправить отладкувывод в любое место.

2 голосов
/ 06 февраля 2012
2 голосов
/ 06 февраля 2012

Это по сути невозможно.
Вы можете манипулировать пользовательским интерфейсом только из потока пользовательского интерфейса.(Пользовательский интерфейс не является потокобезопасным)

Вы можете сделать это быстрее, вызвав BeginUpdate() и EndUpdate(), и вы можете сделать это еще быстрее (но сложнее), используя ListView в виртуальном режиме.

Однако вы не должны отображать 15 000 элементов в lsitbox.
Такой список будет бесполезен при реальном использовании.

1 голос
/ 06 февраля 2012

Вы можете значительно ускорить этот процесс, предотвращая перерисовку ListBox после каждого добавления, добавив цикл for:

listBox1.BeginUpdate();
listBox2.BeginUpdate();
listBox3.BeginUpdate();
listBox4.BeginUpdate();
for (int n = 0; n < 7500; n++)
{
    listBox1.Items.Add(itemList[n, 0].ToString());
    listBox2.Items.Add(itemList[n, 1].ToString());
    listBox3.Items.Add(itemList[n, 2].ToString());
    listBox4.Items.Add(itemList[n, 3].ToString());
}
listBox1.EndUpdate();
listBox2.EndUpdate();
listBox3.EndUpdate();
listBox4.EndUpdate();
1 голос
/ 06 февраля 2012

Вы должны попытаться использовать BeginUpdate / EndUpdate методы:

listbox1.BeginUpdate();
// Adds 5K items
listbox1.EndUpdate();
1 голос
/ 06 февраля 2012
listBox1.BeginUpdate();
listBox2.BeginUpdate();
listBox3.BeginUpdate();
listBox4.BeginUpdate();

for (int n = 0; n < 7500; n++)
{
    listBox1.Items.Add(itemList[n, 0].ToString());
    listBox2.Items.Add(itemList[n, 1].ToString());
    listBox3.Items.Add(itemList[n, 2].ToString());
    listBox4.Items.Add(itemList[n, 3].ToString());
}


listBox1.EndUpdate();
listBox2.EndUpdate();
listBox3.EndUpdate();
listBox4.EndUpdate();

Это задержит рисование, пока все элементы не будут добавлены, поэтому должно быть быстрее.

0 голосов
/ 06 февраля 2012

Я просто хочу собрать ответы каждого. Вы действительно должны обновлять элементы в вашей ветке GUI, иначе вы можете получить неожиданные результаты. Чтобы гарантировать, что код работает в потоке GUI, а ваш список не перерисовывает себя каждый раз при добавлении (), вам нужна пара BeingUpdate () и EndUpdate (), как и другие, но для запуска этого в потоке GUI используйте BeingInvoke (), который просто помещает задачу в «очередь потоков GUI», готовую к употреблению. BeingInvoke () вернется немедленно, но ваш запрос будет помещен в очередь.

BeingInvoke () API Док. http://msdn.microsoft.com/en-us/library/0b1bf3y3.aspx

A хорошее обсуждение о BeginInvoke () и почему оно используется.

BeginInvoke((MethodInvoker)delegate
{
    listBox1.BeginUpdate();
    listBox2.BeginUpdate();
    listBox3.BeginUpdate();
    listBox4.BeginUpdate();
    for (int n = 0; n < 7500; n++)
    {
        listBox1.Items.Add(itemList[n, 0].ToString());
        listBox2.Items.Add(itemList[n, 1].ToString());
        listBox3.Items.Add(itemList[n, 2].ToString());
        listBox4.Items.Add(itemList[n, 3].ToString());
    }
    listBox1.EndUpdate();
    listBox2.EndUpdate();
    listBox3.EndUpdate();
    listBox4.EndUpdate();
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...