Добавить элементы в ObservableCollection <t> без блокировки пользовательского интерфейса

77
9

Я пытаюсь добавить элементы в ObservableCollection<ProductSpecification> из таблицы базы данных, используя SqlReader. Вот код:

public void GetProductSpecification()
{
ProductSpecificationList.Clear();

using (var connect = Connection.Connect())
{
string query = "select * from ut_kst_specyfikacje_indeksow_test";

using (SqlCommand cmd = new SqlCommand(query, connect))
{
try
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
ProductSpecificationList.Add(new ProductSpecification()
{
//Here I am setting values of fields from reader[xx]. No parsing/converting errors in here.
//Also tried Dispatcher in here, but it throws exception "Invalid attempt to call MetaData while reader is closed"
});
}

}

}
catch (SqlException e)
{
NLogger.logger.Error(e.Message);
}
}
}
}

Этот метод вызывается в одной из моих команд ICommand привязанных к кнопке. Когда я нажимаю эту кнопку, пользовательский интерфейс замерзает около 10 секунд (в ut_kst_specyfikacje_indeksow_test имеется 45 000 записей). По-моему, это немного медленнее, честно говоря, я ожидал около 2 секунд.

Насколько я знаю, ObservableCollection связан с UI и не может быть обновлен из другого потока, кроме потока пользовательского интерфейса. Я пробовал использовать Dispatcher но это имеет место Исключение:

Недействительная попытка вызвать MetaData, когда читатель закрыт.

Как это сделать?

спросил(а) 2021-01-25T13:03:10+03:00 4 месяца, 2 недели назад
1
Решение
88

Проблема в том, что вы поднимаете уведомление для каждого добавления в ObservableCollection. Это не будет хорошо работать для 45000 предметов

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

var list = new List<ProductSpecification>();

while (reader.Read())
{
list.Add(new ProductSpecification()
{
//Here I am setting values of fields from reader[xx]. No parsing/converting errors in here.
//Also tried Dispatcher in here, but it throws exception "Invalid attempt to call MetaData while reader is closed"
});
}

ProductSpecificationList = new ObservableCollection<ProductSpecification>(list);

Примечание. Предполагается, что ProductSpecificationList вызывает событие с измененным свойством

Также рассмотрите возможность создания async Task всей партии и используйте методы async в ExecuteReaderAsync и аналогичные

Добавить перец и соль по вкусу

ответил(а) 2021-01-25T13:03:10+03:00 4 месяца, 2 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема