数据库管理程序中,如果涉及大容量的数据传输,在数据检索过程中可能导致UI无响应。这里模拟这个过程,并通过异步调用避免UI停滞问题。
该示例有共有3个button和1个DataGridView控件,其中2个button用于分别正常检索数据和异步检索数据,另一个button用于绑定数据。
异步调用实际是开启新的非UI线程处理数据,因此异步调用中弹出的对话框也是和用户UI没关系的。程序中让数据访问延时5秒,尝试拖动窗体看看效果。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Collections;
namespace snippetWinForm
{
public partial class frmSnippet : Form
{
public frmSnippet()
{
InitializeComponent();
}
//Variable declaration
string connectionString = "Data Source=.\\sqlexpress; Initial Catalog=Northwind; Integrated security=true;Asynchronous Processing=true";
string selectString = "waitfor delay '0:0:5'; select productname, quantityPerUnit, unitPrice, unitsInStock, UnitsOnOrder from products; ";
ArrayList al = new ArrayList();
/// <summary>
/// 加载数据,并填充到ArrayList对象;
/// 此为非异步调用,所以大容量数据时可能UI停止响应;
/// 如MessageBox弹出后绑定按钮无法按下。
/// </summary>
private void btnLoad_Click(object sender, EventArgs e)
{
al.Clear();
using (SqlConnection cn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(selectString, cn);
cn.Open();
SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if (dr.HasRows )
{
foreach (var item in dr)
{
al.Add(item);
}
dr.Close();
}
cn.Close();
}
MessageBox.Show("UI Thread:Data Load finished, you can bind the data now!", "Data Load");
}
/// <summary>
/// 异步调用唤起,命令对象cmd执行完毕后执行异步回调AsyncCallback callback
/// </summary>
private void btnLoadDataAsync_Click(object sender, EventArgs e)
{
al.Clear();
SqlConnection cn = new SqlConnection(connectionString);//此处若用using语句包括,将无法实现异步调用!!!
{
SqlCommand cmd = new SqlCommand(selectString, cn);
cn.Open();
AsyncCallback callback = new AsyncCallback(DataReaderIsReady);
IAsyncResult asyncResult = cmd.BeginExecuteReader(callback, cmd);
}
}
/// <summary>
/// 回调方法,在命令cmd执行完毕后调用该callback方法;
/// AsyncCallback callback = new AsyncCallback(DataReaderIsReady);
/// IAsyncResult asyncResult = cmd.BeginExecuteReader(callback, cmd);
/// </summary>
/// <param name="result"></param>
private void DataReaderIsReady(IAsyncResult result)
{
//因为是异步调用,所以这个MessageBox是非模式的对话框,可以继续点击UI。
//问题:在MessageBox显示的时候点击绑定按钮(此时ArrayList为空),然后确定MessageBox,此时尽管ArrayList有数据,但也无法绑定,WHY?
MessageBox.Show("Asynchronous callback ,None UI Thread : Result Load Complete!", "I'm Done!");
SqlCommand cmd = (SqlCommand)result.AsyncState;
SqlDataReader dr = cmd.EndExecuteReader(result);
if (dr.HasRows)
{
foreach (var item in dr)
{
al.Add(item);
}
}
dr.Close();
cmd.Connection.Dispose();
//btnBind.Enabled = true; //因为该方法在另外的非UI先线程里,所以对btnBind不可见!
}
/// <summary>
/// 只需要将DataGridView的DataSource指定为ArrayList对象,就完成了绑定。
/// </summary>
private void btnBind_Click(object sender, EventArgs e)
{
dgvProducts.DataSource = al;
}
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Collections;
namespace snippetWinForm
{
public partial class frmSnippet : Form
{
public frmSnippet()
{
InitializeComponent();
}
//Variable declaration
string connectionString = "Data Source=.\\sqlexpress; Initial Catalog=Northwind; Integrated security=true;Asynchronous Processing=true";
string selectString = "waitfor delay '0:0:5'; select productname, quantityPerUnit, unitPrice, unitsInStock, UnitsOnOrder from products; ";
ArrayList al = new ArrayList();
/// <summary>
/// 加载数据,并填充到ArrayList对象;
/// 此为非异步调用,所以大容量数据时可能UI停止响应;
/// 如MessageBox弹出后绑定按钮无法按下。
/// </summary>
private void btnLoad_Click(object sender, EventArgs e)
{
al.Clear();
using (SqlConnection cn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(selectString, cn);
cn.Open();
SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if (dr.HasRows )
{
foreach (var item in dr)
{
al.Add(item);
}
dr.Close();
}
cn.Close();
}
MessageBox.Show("UI Thread:Data Load finished, you can bind the data now!", "Data Load");
}
/// <summary>
/// 异步调用唤起,命令对象cmd执行完毕后执行异步回调AsyncCallback callback
/// </summary>
private void btnLoadDataAsync_Click(object sender, EventArgs e)
{
al.Clear();
SqlConnection cn = new SqlConnection(connectionString);//此处若用using语句包括,将无法实现异步调用!!!
{
SqlCommand cmd = new SqlCommand(selectString, cn);
cn.Open();
AsyncCallback callback = new AsyncCallback(DataReaderIsReady);
IAsyncResult asyncResult = cmd.BeginExecuteReader(callback, cmd);
}
}
/// <summary>
/// 回调方法,在命令cmd执行完毕后调用该callback方法;
/// AsyncCallback callback = new AsyncCallback(DataReaderIsReady);
/// IAsyncResult asyncResult = cmd.BeginExecuteReader(callback, cmd);
/// </summary>
/// <param name="result"></param>
private void DataReaderIsReady(IAsyncResult result)
{
//因为是异步调用,所以这个MessageBox是非模式的对话框,可以继续点击UI。
//问题:在MessageBox显示的时候点击绑定按钮(此时ArrayList为空),然后确定MessageBox,此时尽管ArrayList有数据,但也无法绑定,WHY?
MessageBox.Show("Asynchronous callback ,None UI Thread : Result Load Complete!", "I'm Done!");
SqlCommand cmd = (SqlCommand)result.AsyncState;
SqlDataReader dr = cmd.EndExecuteReader(result);
if (dr.HasRows)
{
foreach (var item in dr)
{
al.Add(item);
}
}
dr.Close();
cmd.Connection.Dispose();
//btnBind.Enabled = true; //因为该方法在另外的非UI先线程里,所以对btnBind不可见!
}
/// <summary>
/// 只需要将DataGridView的DataSource指定为ArrayList对象,就完成了绑定。
/// </summary>
private void btnBind_Click(object sender, EventArgs e)
{
dgvProducts.DataSource = al;
}
}
}