Как сделать асинхронное неблокирующее чтение с ожиданием результата?
Есть задача: загрузить данные из таблицы БД в DataTable. Так как данных достаточно много и сервер зело задумчивый, собираюсь воспользоваться асинхронными методами, но почему-то ничего не работает как заявлено. Есть такой код:
public void LoadData()
{
LoadDataAsync();
}
protected async Task LoadDataAsync()
{
// какой-то подготавливающий код - неинтересные, скучные подробности
await _dataAdapter.Fill(_dataTable);
// другой код, установка переменных и прочие действия
}
После вызова LoadData() вторая часть метода LoadDataAsync() просто не выполняется и выполнение передается в функцию, которая вызывала LoadData(). И, значит, таблица пуста. Пробовал так:
public async void LoadData()
{
await LoadDataAsync();
}
Создавал Task-и и вызывал через Run с await-ом и через await Task.WhenAll(t) в обоих методах, один делал с префиксом async, второй нет, пробовал разные их комбинации. Пока добился ожидания следующим образом:
public void LoadData()
{
Task _res = Task.Run(LoadDataAsync);
Task.WaitAll(_res);
}
Код для LoadDataAsync() как показан выше.
Отсюда вопрос: как сделать корректно загрузку данных, чтобы не было блокировки и организовать ожидание загрузки данных в память?
Спасибо
Ответы (1 шт):
На данный момент эта функция вызывается из конструктора.
В конструктор нельзя вставлять свой код из-за всякого рода ограничений, связанных с не до конца проинициализированным окном на момент выполнения конструктора. Вместо конструктора используйте событие Window.Loaded и его обработчик, и в нём уже можно сразу использовать асинхронность.
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
// здесь можно сделать что-то до начала загрузки
await LoadDataAsync();
// здесь что-то после, можно взаимодействовать с контролами
}
private async Task LoadDataAsync()
{
// ...
await _dataAdapter.Fill(_dataTable);
// ...
}
Перенесите весь свой код из конструктора в обработчик события Window.Loaded, оставьте в конструкторе только родной InitializeComponent().
Еще почитайте эту статью.
Если же вы просто хотите запустить параллельную загрузку, то это можно сделать без асинхронности, а просто запуском задачи.
private void LoadData()
{
// ...
_dataAdapter.Fill(_dataTable).Wait();
// ...
}
Вызов
Task.Run(() => LoadData());