无法取消按钮单击时的异步/等待呼叫

时间:2016-12-11 19:13:04

标签: c# async-await

我无法在取消按钮点击时取消async / await调用。如果在网格中加载数据需要很长时间,我想取消查询。我是新手使用async / await方法并参考了很多例子,但是如果不能锻炼。请看下面的代码,请帮忙。感谢

    namespace MyFirstAsync
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        CancellationTokenSource cts ;
        private async void btnExecute_Click(object sender, EventArgs e)
        {
            cts = new CancellationTokenSource();
            try
            {
                string connectionString = "Data Source=G50-80;Initial Catalog=HPSF_Compdb;User ID=sa;Password=sql@2012";
                string sqlQuery = "select top 900000 * from requestevent.result";
                SqlConnection conn = new SqlConnection(connectionString);
                SqlCommand cmd = new SqlCommand(sqlQuery, conn);
                await conn.OpenAsync(cts.Token);
                SqlDataReader reader = await cmd.ExecuteReaderAsync(cts.Token);
                DataTable dt = new DataTable();
                //cts.Cancel();
                await Task.Run(() => dt.Load(reader), cts.Token);
                gvData.Invoke(new gvDelegate(UpdateDataToGrid), new object[] { dt });
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        public delegate void gvDelegate(DataTable dt);
        public void UpdateDataToGrid(DataTable dt)
        {
            gvData.DataSource = dt;
        }



        private void btncancel_Click(object sender, EventArgs e)
        {
            cts.Cancel();
        }



    }
}

2 个答案:

答案 0 :(得分:0)

问题在于这行代码:

await Task.Run(() => dt.Load(reader), cts.Token);

与您的期望相反,传递给CancellationToken的{​​{1}}仅取消该任务的开始,而不取消任务本身。换句话说,一旦Task.Run开始,就无法取消。

理想情况下,您应该在现代代码中使用Load以外的其他内容;其他数据库API已更新,以支持取消。如果无法做到这一点,那么您可以在答案中使用DataTable。但是,您应该使用CancellationTokenRegistration - 改为使用Result

await

答案 1 :(得分:-1)

我找到了上述问题的解决方案,只是改变了数据加载到数据表的方式。请使用新代码替换已注释的旧代码,并且按预期工作正常。新代码我只是复制和粘贴,但我仍然不知道如何描述新代码的工作方式,因为我是新手。但这对我有用。如果您区分两者,请解释一下。

using (CancellationTokenRegistration ctr = cts.Token.Register(() => cmd.Cancel()))
            {
                using (var reader = cmd.ExecuteReaderAsync(cts.Token))
                {
                    dt.Load(reader.Result);
                }
            }
            //SqlDataReader reader = await cmd.ExecuteReaderAsync(cts.Token);
            //DataTable dt = new DataTable();
            //await Task.Run(() => dt.Load(reader), cts.Token);