Обновление пользовательского интерфейса фонового исполнителя C#

Я пытаюсь использовать фонового рабочего, чтобы получить большой объем данных из базы данных без остановки основного потока. Кажется, это работает хорошо, за исключением того, что когда дело доходит до обновления пользовательского интерфейса, обновление зависает на экране. Соответствующий код следующим образом:

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {               
        lvwTest.BeginUpdate();
        lvwTest.Items.Clear();

        // Populate the UI
        foreach (TestItem ti in testData)
        {
            ListViewItem lvi = lvwTest.Items.Add(ti.Value1);
            lvi.SubItems.Add(ti.Value2);
        }

        lvwTest.EndUpdate();                     
    }

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


person Paul Michaels    schedule 04.08.2010    source источник


Ответы (4)


Я рекомендую загрузить данные в память и использовать виртуальный режим ListView. Таким образом, вы создаете объекты ListViewItem только по мере необходимости.

person Stephen Cleary    schedule 04.08.2010

Если вам нужно загрузить действительно огромное количество данных в пользовательский интерфейс, это потребует времени и заблокирует наше приложение. Опция — умная прокрутка или разбиение на страницы. Вы загружаете все данные, но размещаете их по частям по запросу пользователя.

person Andrey    schedule 04.08.2010

Поскольку большинство из вышеперечисленного являются хорошими советами, но на самом деле не решают вашей непосредственной проблемы, вот еще один подход: это обновит ваш графический интерфейс и сохранит его отзывчивость. Предполагая, что вы находитесь в приложении WinForm?

        Application.DoEvents();
        this.Refresh();

Тем не менее, это не значит, что, может быть, не стоит прислушиваться к идеям свыше :-)

person Remy    schedule 04.08.2010
comment
Это приложение WinForm, но еще во времена VB6 DoEvents не одобрялось, потому что оно могло изменить последовательность событий. Разве это не так в С#? - person Paul Michaels; 05.08.2010
comment
Возможно, вы правы, это все еще немного взломано из того, что я слышал. Зависит от сложности вашего приложения. Я переписал свое последнее простое приложение на WPF, это действительно хороший фреймворк. - person Remy; 06.08.2010

Помимо виртуализации, я бы рекомендовал разбивать элементы на пакеты, скажем, по 100 штук и добавлять каждый пакет в отдельное сообщение. Таким образом, пользовательский интерфейс обрабатывает другие сообщения, пока пакеты добавляются в файл ListView.

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

person Kent Boogaart    schedule 04.08.2010