How to populate the datagrid on background thread with data binding by using Visual C#
2007-05-16 00:25
901 查看
How to populate the datagrid on background thread with data binding by using Visual C#
View products that this article applies to.function loadTOCNode(){}
Article ID | : | 318607 |
Last Review | : | September 15, 2005 |
Revision | : | 3.0 |
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 |
SUMMARY
Requirements
Background
Build the Windows Forms application
Demonstration
Complete code Listing
REFERENCES
var sectionFilter = "type != 'notice' && type != 'securedata' && type != 'querywords'";
var tocArrow = "/library/images/support/kbgraphics/public/en-us/downarrow.gif";
var depthLimit = 10;
var depth3Limit = 10;
var depth4Limit = 5;
var depth5Limit = 3;
var tocEntryMinimum = 1;
.toc{display: none;}
SUMMARY
loadTOCNode(1, '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
loadTOCNode(2, 'summary');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
loadTOCNode(2, 'summary');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
loadTOCNode(2, 'summary');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:[code] using System.Threading; using System.Data.SqlClient; [/code] |
10. | Add the following code immediately below the Windows Forms Designer Generated Code:[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;"); [/code]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:[code] UpdateThread = new Thread(UpdateThreadStart); UpdateThread.Name = "Update Thread"; UpdateThread.IsBackground = true; UpdateThread.Start(); [/code] |
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:[code] QueryDataBase(); [/code] |
14. | Paste the following code below the button events that you added in the earlier steps:[code] // 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); } [/code]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:[code] MyForm = new Form1(); Application.Run(MyForm); [/code] |
16. | Press CTRL+SHIFT+B to build your application. |
Back to the top
Demonstration
loadTOCNode(2, 'summary');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
loadTOCNode(2, 'summary');[code] 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); } } }
[/code]
相关文章推荐
- How To Read and Write BLOB Data by Using ADO.NET with Visual C# .NET
- How To Read and Write BLOB Data by Using ADO.NET with Visual C# .NET
- How to send raw data to a printer by using Visual C# .NET
- How to authenticate against the Active Directory by using Forms authentication and Visual C# .NET
- How To Transfer XML Data to Microsoft Excel 2002 by Using Visual C# .NET
- How to automate PowerPoint by using Visual C++ 5.0 or Visual C++ 6.0 with The Microsoft Foundation Classes
- How to transfer data to an Excel workbook by using Visual C# 2005 or Visual C# .NET
- How To Display Hierarchical Data by Using Nested Repeater Controls and Visual C# .NET(ZT)
- How to write to an event log by using Visual C#
- How to synchronize access to a shared resource in a multithreading environment by using Visual C#
- [转]how to split the ng-repeat data with three columns using bootstrap
- How To Binding the DataContext Property To DataGrid
- How To Display Hierarchical Data by Using Nested Repeater Controls and Visual
- How to add HTML code to the clipboard by using Visual Basic Or VBA
- How to write an application that supports the Fast User Switching feature by using Visual Basic .NET or Visual Basic
- How To Create an ASP.NET HTTP Handler by Using Visual C# .NET
- How To Check Whether Physical Standby is in Sync with the Primary or Not?
- How to get the password text in a text with password property from another process using C++ - 用C++如何从不同进程获取密码框文本
- How to check the MS SQL Server job run status by using Script
- HOW TO: Upload a File to a Web Server in ASP.NET by Using Visual Basic .NET