惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Hacker News
The Hacker News
博客园_首页
人人都是产品经理
人人都是产品经理
博客园 - 聂微东
J
Java Code Geeks
Stack Overflow Blog
Stack Overflow Blog
Blog — PlanetScale
Blog — PlanetScale
博客园 - 三生石上(FineUI控件)
A
About on SuperTechFans
V
Visual Studio Blog
小众软件
小众软件
MyScale Blog
MyScale Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
F
Full Disclosure
酷 壳 – CoolShell
酷 壳 – CoolShell
T
The Exploit Database - CXSecurity.com
C
CERT Recently Published Vulnerability Notes
T
Threat Research - Cisco Blogs
AWS News Blog
AWS News Blog
T
Tor Project blog
Jina AI
Jina AI
GbyAI
GbyAI
C
Comments on: Blog
IT之家
IT之家
Apple Machine Learning Research
Apple Machine Learning Research
A
Arctic Wolf
有赞技术团队
有赞技术团队
SecWiki News
SecWiki News
L
Lohrmann on Cybersecurity
Security Latest
Security Latest
Webroot Blog
Webroot Blog
C
Cisco Blogs
雷峰网
雷峰网
云风的 BLOG
云风的 BLOG
博客园 - 叶小钗
K
Kaspersky official blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
宝玉的分享
宝玉的分享
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
O
OpenAI News
H
Hacker News: Front Page
D
Darknet – Hacking Tools, Hacker News & Cyber Security
D
Docker
P
Palo Alto Networks Blog
The Register - Security
The Register - Security
B
Blog RSS Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
WordPress大学
WordPress大学
阮一峰的网络日志
阮一峰的网络日志

博客园 - 白沙

自定义鼠标右键弹出式菜单 web菜单的实现【zt】 深入浅出理解索引结构[zt] 你真的了解.NET中的String吗? 堆和栈的区别 软件团队的建设和软件开发管理[zz老秦] 简单的SOCKET传送文件和字符串实现 类与结构的区别 C#中ref和out的使用小结 CSS中expression使用简介(转载) 特效:CSS+Javascript实现表格背景变色 C#箴言:定义常量的两种方法 网页弹出窗口代码【来源于网络】 注意document中需要对象的方式,区别下面四种 jsp对checkbox的操作 div的操作 Good morning I'm very happy to come here to study with you 在 ASP.NET 中执行 URL 重写
How to populate the datagrid on background thread with data binding by using Visual C#
白沙 · 2007-05-16 · via 博客园 - 白沙

How to populate the datagrid on background thread with data binding by using Visual C#

Article ID : 318607
Last Review : September 15, 2005
Revision : 3.0

This article was previously published under Q318607

For a Microsoft Visual Basic .NET version of this article, see 318604 (http://support.microsoft.com/kb/318604/).

This article refers to the following Microsoft .NET Framework Class Library namespaces:

System.Threading
System.Data
System.Data.SqlClient
On This Page

SUMMARY

This step-by-step article shows you how to query a database on a background thread and use databinding to display the results in a DataGrid object.

When large queries to a database are executed, the application may become unresponsive for a long period of time. To avoid this behavior and decrease the waiting time of the user, the query can be executed on a background thread, releasing the application for other tasks until the data is returned from the database and databinding is performed.

Back to the top

Requirements

The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:

Microsoft Visual Studio .NET
Access to the Northwind sample database

Back to the top

Background

By design, Windows Form or Control methods cannot be called on a thread other than the one that created the form or control. If you attempt to do this, an exception is thrown. Depending on the exception handling implemented in your code, this exception may cause your application to terminate. If no exception handling is implemented, the following error message is displayed:

An unhandled exception of type 'System.ArgumentException' occurred in system.windows.forms.dll

Additional information: Controls created on one thread cannot be parented to a control on a different thread.

The exception is raised because Windows Forms are based on a single-threaded apartment (STA) model. Windows Forms can be created on any thread; after they are created, however, they cannot be switched to a different thread. In addition, the Windows Form methods cannot be accessed on another thread; this means that all method calls must be executed on the thread that created the form or control.

Method calls that originate outside the creation thread must be marshaled (executed) on the creation thread. To do this asynchronously, the form has a BeginInvoke method that forces the method to be executed on the thread that created the form or control. The synchronous method call is done with a call to the Invoke method.

Back to the top

Build the Windows Forms application

This section describes how to create a Windows Form application that queries a database on a background thread and uses the BeginInvoke method to perform databinding on a DataGrid.

1. Start Visual Studio .NET.
2. Create a new project, select Visual C# as the Project Type, and use the Windows Application template.
3. Add a Button object to the form, and change its Text property to "Query on Thread".
4. Add another Button to the form, and change its Text property to "Query on Form".
5. Add a Label to the form, and clear its Text property.
6. Add a TextBox to the form.
7. Add a DataGrid to the form.
8. Right-click the form, and then click View Code; this displays the code of your application.
9. Add the following using statements to the top of the page in order to use the Threading and SqlClient namespaces:
   using System.Threading;
            using System.Data.SqlClient;
10. Add the following code immediately below the Windows Forms Designer Generated Code:
   static Form1 MyForm;
            Thread UpdateThread;
            ThreadStart UpdateThreadStart = new ThreadStart(QueryDataBase);
            static MethodInvoker CallDataBindToDataGrid = new MethodInvoker(DataBindToDataGrid);
            static DataSet MyDataSet;
            static SqlDataAdapter MyDataAdapter;
            static string MyQueryString = "SELECT [Order Details].*, Orders.CustomerID, Orders.EmployeeID, Orders.OrderDate FROM [Order Details] CROSS JOIN Orders";
            static SqlConnection MyConnection = new SqlConnection("data source=localhost;initial catalog=Northwind;integrated security=SSPI;");
Note The query used in this demonstration is a Cartesian Product that returns over 165,000 rows from the Northwind database. The amount of data returned is large so that the responsiveness of the form can be demonstrated.
11. Open the Windows Forms Design view.
12. Double-click the Query on Thread button, and paste the following code in the Click event for this button:
   UpdateThread = new Thread(UpdateThreadStart);
            UpdateThread.Name = "Update Thread";
            UpdateThread.IsBackground = true;
            UpdateThread.Start();
13. Open the Design view again, and then double-click the Query on Form button. Paste the following code in the Click event for this button:
   QueryDataBase();
14. Paste the following code below the button events that you added in the earlier steps:
   // Sub routine that is to be executed on Form's thread.
            static void DataBindToDataGrid()
            {
            MyForm.dataGrid1.DataSource = MyDataSet;
            MyForm.dataGrid1.DataMember = "MyTable";
            MyDataSet = null;
            MyDataAdapter = null;
            }
            // Sub routine used by the background thread to query database.
            static void QueryDataBase()
            {
            MyDataSet = new DataSet();
            MyConnection.Open();
            MyDataAdapter = new SqlDataAdapter(MyQueryString, MyConnection);
            MyForm.label1.Text = "Filling the DataSet";
            MyDataAdapter.Fill(MyDataSet, "MyTable");
            MyConnection.Close();
            MyForm.label1.Text = "DataSet Filled";
            MyForm.BeginInvoke(CallDataBindToDataGrid);
            }
These Sub routines are used by the background thread to query the database and databind it to the DataGrid located on the Windows Form when the first button is clicked. The Click event of the second button calls the QueryDataBase Sub routine directly, and will be executed on the Windows Form thread.
15. Modify the main function to look as follows:
   MyForm = new Form1();
            Application.Run(MyForm);
16. Press CTRL+SHIFT+B to build your application.

Back to the top

Demonstration

To see the benefit that is gained by using a background thread to query the database, follow these steps:

1. Press CTRL+F5 to execute your application without debugging.
2. Click the Query on Form button. This begins the query on the Windows Forms thread. If you then try to enter some text in the text box that is displayed on the form, the application does not respond. After the query has completed (this may take some time, depending on your computer), the DataGrid displays the results of the query.
3. Click the Query on Thread button. This creates a background thread that queries the database and keeps the application responsive to user interaction. To see this, click the button, and then type some text in the text box on the form.

Back to the top

Complete code Listing

   using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
using System.Data.SqlClient;
namespace DataGridThread
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.DataGrid dataGrid1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.TextBox textBox1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.dataGrid1 = new System.Windows.Forms.DataGrid();
this.button1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.button2 = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).BeginInit();
this.SuspendLayout();
//
// dataGrid1
//
this.dataGrid1.DataMember = "";
this.dataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.dataGrid1.Location = new System.Drawing.Point(8, 8);
this.dataGrid1.Name = "dataGrid1";
this.dataGrid1.Size = new System.Drawing.Size(736, 208);
this.dataGrid1.TabIndex = 0;
//
// button1
//
this.button1.Location = new System.Drawing.Point(16, 232);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(120, 23);
this.button1.TabIndex = 1;
this.button1.Text = "Query on Thread";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// label1
//
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 15F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label1.Location = new System.Drawing.Point(16, 276);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(720, 24);
this.label1.TabIndex = 2;
//
// button2
//
this.button2.Location = new System.Drawing.Point(144, 232);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(112, 23);
this.button2.TabIndex = 3;
this.button2.Text = "Query on Form";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(268, 232);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(472, 20);
this.textBox1.TabIndex = 4;
this.textBox1.Text = "";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(752, 330);
this.Controls.AddRange(new System.Windows.Forms.Control[] { this.textBox1, this.button2, this.label1, this.button1, this.dataGrid1});
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).EndInit();
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
///
static Form1 MyForm;
Thread UpdateThread;
ThreadStart UpdateThreadStart = new ThreadStart(QueryDataBase);
static MethodInvoker CallDataBindToDataGrid = new MethodInvoker(DataBindToDataGrid);
static DataSet MyDataSet;
static SqlDataAdapter MyDataAdapter;
static string MyQueryString = "SELECT Products.* FROM [Order Details] CROSS JOIN Products";
static SqlConnection MyConnection = new SqlConnection("data source=localhost;initial catalog=Northwind;integrated security=SSPI;");
[STAThread]
static void Main()
{
MyForm = new Form1();
Application.Run(MyForm);
}
private void Form1_Load(object sender, System.EventArgs e)
{
}
private void button1_Click(object sender, System.EventArgs e)
{
UpdateThread = new Thread(UpdateThreadStart);
UpdateThread.Name = "Update Thread";
UpdateThread.IsBackground = true;
UpdateThread.Start();
}
private void button2_Click(object sender, System.EventArgs e)
{
QueryDataBase();
}
static void DataBindToDataGrid()
{
MyForm.dataGrid1.DataSource = MyDataSet;
MyForm.dataGrid1.DataMember = "MyTable";
MyDataSet = null;
MyDataAdapter = null;
}
static void QueryDataBase()
{
MyDataSet = new DataSet();
MyConnection.Open();
MyDataAdapter = new SqlDataAdapter(MyQueryString, MyConnection);
MyForm.label1.Text = "Filling the DataSet";
MyDataAdapter.Fill(MyDataSet, "MyTable");
MyConnection.Close();
MyForm.label1.Text = "DataSet Filled";
MyForm.BeginInvoke(CallDataBindToDataGrid);
}
}
}