В небольшом приложении получаю данные из SQL во ViewModel напрямую через SqlCommand.ExecuteReaderAsync()
и SqlDataReader.ReadAsync()
. Полученная коллекция Collection<T>
отображается в DataGrid
. Запрос не быстрый, но такая связка позволяет не блокировать UI, и DataGrid
заполняется по мере поступления данных из SQL, что хорошо.
Решил перенести запрос в DataLayer, создал async-метод GetCollectionAsync()
. UI по прежнему не блокируется, но теперь DataGrid заполняется только после получения всей коллекции. Получается, что я выиграл от разделения кода на уровни, но проиграл в функциональности. Что я делаю не так?
Было:
public class ViewModel
{
public ICollection<Order> colOrders;
public async void GetDataAsync()
{
using (SqlConnection sqlConnect = new qlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("select Id, Customer from Orders", sqlConnect);
sqlConnect.Open();
SqlDataReader reader = await cmd.ExecuteReaderAsync();
if (reader.HasRows)
{
while (await reader.ReadAsync())
{
colOrders.Add(new Order(reader["Id"], reader["Customer"]));
}
}
reader.Close();
}
}
}
Стало:
public class ViewModel
{
public ICollection<Order> colOrders;
protected async void GetDataAsync() {
DataLayer dl = new DataLayer();
colOrders = await dl.GetDataAsync();
}
}
Код в Task<ICollection<Order>>DataLayer.GetDataAsync()
делает всё то же самое, что и предыдущий.
Всякие try...catch для простоты опускаю.
Можете сделать примерно так. С обычными IEnumerable
будет сложно, а здесь вы просто подписываетесь на событие, которое запускается при добавлении новых записей:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var collection = new ObservableCollection<string>();
collection.CollectionChanged += (s, args) =>
{
if (args.Action == NotifyCollectionChangedAction.Add)
foreach (string value in args.NewItems)
listbox.Items.Add(value);
};
await GetData(collection);
}
private async Task GetData(ObservableCollection<string> collection)
{
for (int i = 0; i < 10; i++)
{
await Task.Delay(1000);
collection.Add("Item-" + i);
}
}
Нашел устраивающий меня вариант решения (спасибо Zergatul, натолкнул на идею).
Вместо
protected async void GetDataAsync() {
DataLayer dl = new DataLayer();
colOrders = await dl.GetDataAsync();
}
стал передавать коллекцию как параметр в DataLayer, а выход поменял на bool. Получилось:
protected async void GetDataAsync() {
DataLayer dl = new DataLayer();
bool isOK = await dl.FillDataAsync(colOrders);
}
UI не блокируется, коллекция к моменту вызова DataLayer
у меня уже есть, данные вываливаются в DataGrid
порциями - всё как я хотел.
Есть ли какая-то разница между присваиванием нового значение DataRow через DataRowExtensionsSetField и через индексатор по имени?
У меня возникла проблема с элементарной отправкой post запросаПока я гуглил, еще больше запутался