У меня возникли некоторые проблемы с работой асинхронной операции (новинка для асинхронной работы). Моя цель состоит в том, чтобы кнопка «Загрузить данные» вышла и извлекла некоторые данные из базы данных и заполнила сетку. Для некоторых пользователей база данных может быть довольно далеко, и эта операция может занять некоторое время. Учитывая это, я хочу, чтобы пользователи имели возможность отменить и выбрать получение меньшего набора данных.
У меня он в основном работает с током:
- Пользователь нажимает кнопку «Загрузить данные ...»
- Кнопка меняется на «Отмена» и
Асинхронная операция для извлечения данных начинается
- Данные получены и
сетка заполнена
Это все работает хорошо, ЗА ИСКЛЮЧЕНИЕМ, если пользователь нажимает кнопку «Отмена», все равно требуется столько же времени, сколько потребовалось бы для того, чтобы все данные для сетки оказались пустыми. Это заставляет меня поверить, что длительная операция на самом деле не была отменена ... однако, когда я отлаживаю в методе «FindForLocationAsync», токен отмены действительно останавливает итеративную операцию и рано возвращается из метода, если пользователь запрашивает отмена.
Я читал об этом столько времени, сколько мог, но сейчас я в некотором тупике. Любая помощь будет принята с благодарностью.

Источник токена отмены
CancellationTokenSource cancellationTokenSource = null;
Метод нажатия кнопки
private async void btnSearch_Click(object sender, EventArgs e)
{
gridLog.DataSource = null;
Cursor = Cursors.WaitCursor;
if (btnSearch.Text.ToLower().Contains("load"))
{
btnSearch.Text = "Cancel";
btnSearch.ForeColor = Color.White;
btnSearch.BackColor = Color.Red;
//get params to pass
/* snip */
cancellationTokenSource = new CancellationTokenSource();
await Task.Run(() =>
{
var ds = DocLog.FindForLocationAsync(docType, subType, days, currLocation.ID, cancellationTokenSource.Token).Result;
gridLog.DataSource = ds;
});
btnSearch.Text = "Load Data...";
btnSearch.ForeColor = Color.Black;
btnSearch.BackColor = Color.FromArgb(225, 225, 225);
}
else
{
cancelSearch();
btnSearch.Text = "Load Data...";
btnSearch.ForeColor = Color.Black;
btnSearch.BackColor = Color.FromArgb(225, 225, 225);
}
Cursor = Cursors.Default;
}
Способ отмены
private void cancelSearch()
{
if (cancellationTokenSource != null) cancellationTokenSource.Cancel();
}
Метод длительного бега
public async static Task<BindingList<DocLog>> FindForLocationAsync(string DocType, string SubType, int? LastXDays, Guid LocationID, CancellationToken CancellationToken)
{
BindingList<DocLog> dll = new BindingList<DocLog>();
using (SqlConnection sqlConnection = new SqlConnection(Helper.GetConnectionString()))
{
sqlConnection.Open();
using (SqlCommand sqlCommand = new SqlCommand((LastXDays == null) ? "DocLogGetAllForLocation" : "DocLogGetAllForLocationLastXDays", sqlConnection))
{
sqlCommand.CommandType = System.Data.CommandType.StoredProcedure;
sqlCommand.Parameters.Add("@DocType", SqlDbType.NVarChar, 30).Value = DocType.Trim();
sqlCommand.Parameters.Add("@SubType", SqlDbType.NVarChar, 30).Value = SubType.Trim();
sqlCommand.Parameters.Add("@LocationID", SqlDbType.UniqueIdentifier).Value = LocationID;
if (LastXDays != null) { sqlCommand.Parameters.Add("@NumberOfDays", SqlDbType.Int).Value = LastXDays; }
SqlDataReader sqlDataReader = sqlCommand.ExecuteReader();
await Task.Run(() =>
{
while (sqlDataReader.Read())
{
if (CancellationToken.IsCancellationRequested)
{
dll = new BindingList<DocLog>();
break;
}
else
{
DocLog dl = readData(sqlDataReader);
dll.Add(dl);
}
}
});
}
}
return dll;
}