最佳实践扩展Windows窗体DataGridView控件 .net 4.5 附示例代码   1.最佳实践扩展Windows窗体DataGridView控件 2.虚拟模式的Windows窗体DataGridView控件 3.介绍:在Windows窗体DataGridView控件中实现虚拟模式 4.如何:实现虚拟模式的即时数据加载Windows窗体DataGridView控制

.net 4.5

 

控制可以消耗大量的内存开销,除非你仔细地使用它。 在客户有限的内存,你可以避免一些这方面的开销,避免内存成本高的特性。 你也可以管理的部分或全部数据维护和检索任务自己使用虚拟模式为了定制的内存使用情况。

在这一节中

 
最佳实践扩展Windows窗体DataGridView控件

控制,避免了不必要的内存使用和在处理大量数据时的性能损失。

虚拟模式的Windows窗体DataGridView控件

描述如何使用虚拟模式来补充或替换标准的数据绑定机制。

介绍:在Windows窗体DataGridView控件中实现虚拟模式

描述如何实现事件处理程序几个虚拟方式。 还演示了如何实现行级回滚并为用户编辑提交。

实现虚拟模式的即时数据加载Windows窗体DataGridView控件

描述如何加载数据的需求,这是非常有用的,当你有更多的数据比可用来显示客户端内存可以存储。

1.最佳实践扩展Windows窗体DataGridView控件

.net 4.5
 
 

控制的目的是提供最大的可伸缩性。 如果你需要显示大量数据,您应该遵循的指导方针中描述这个话题避免消耗大量内存或有辱人格的用户界面(UI)的响应能力。 本主题讨论以下问题:

  • 有效使用单元格样式

  • 有效使用快捷菜单

  • 有效地使用自动调整

  • 使用选定的单元格、行和列的集合

  • 使用共享的行

  • 防止行成为非共享

有效使用单元格样式

 

元素可以是低效的,特别是当处理大量的数据。 为了避免影响性能,使用以下指南:

  • 财产。

有效使用快捷菜单

 

元素将对性能造成负面影响。 为了避免这种惩罚,使用以下指南:

  • 财产为整个控制指定一个快捷菜单。

  • 事件。 这些事件让你管理自己的快捷菜单对象,允许您调整性能。

有效地使用自动调整

 

控制必须检查每个单元格的值,它必须适应。 在处理大型数据集时,这种分析可能会对性能造成负面影响的控制自动调整发生时。 为了避免性能损失,使用以下指南:

  • 控制大量的行。 如果你使用自动分级,只有调整基于显示的行。 只使用在虚拟显示的行模式。

    • 枚举。

    • 枚举。

  • 最大的可伸缩性,关掉自动分级和使用程序化的调整。

使用选定的单元格、行和列的集合

 

控制,许多列少于行。 为了避免性能损失在处理这些集合时,使用以下指南:

  • 方法。 但是请注意,这个方法会导致行成为非共享。 有关更多信息,请参见下一节。

  • 方法来确定选定元素的数量,而不是访问选定的行和列的集合。

使用共享的行

 

类。

可以很容易地共享行实例节省内存,行成为非共享。 例如,每当用户直接与细胞相互作用,成为非共享它的行。 因为这无法避免,这一主题的指导方针是有用的只有当处理大量数据,只有当用户将与一个相对较小的数据每次运行你的程序的一部分。

控件绑定到一个外部数据源或当你实现虚拟模式,提供自己的数据源,细胞外的值存储控制,而不是在细胞对象,允许行共享。

对象只能共享一行如果可以确定所有的细胞状态的行和列的状态包含细胞。 如果你改变一个细胞的状态,这样就可以不再是推断从国家的行和列,行不能共享。

例如,一行不能共享在下列情况下:

  • 的行包含一个选择单元选择的列。

  • 属性集。

  • 属性集。

事件。

。 使用以下指南以确保行共享:

  • 收集。 这些过载自动创建专有的行。

  • 房地产可以共享在下列情况下:

    • 收集。

    • 财产。

    • 财产。

  • 收集。

  • 收集。

属性值为1。

防止行成为非共享

 

事件确定当行成为非共享。 这是有用的调试row-sharing问题时。

为了防止行成为非共享,使用以下指南:

  • 方法,操作行采取行索引参数而不是行实例。 此外,row-related事件接收事件参数处理程序对象与行属性,您可以使用它们来操纵行没有使它们成为非共享。

  • 属性相反,它将使用共享的行索引1和不会检索正确的快捷菜单。

  • 属性检索当前单元格的行和列索引没有直接访问单元。

  • 方法,提高这些事件。

  • 。 这将导致所有选定行成为非共享。

  • 方法。 这种方法会导致行成为非共享。

  • 。 这将导致所有行成为非共享。

  • 。 这将导致所有行成为非共享。

  • 财产。 这将导致所有行成为非共享。

  • 方法。 排序与一个定制的比较器使所有行成为非共享。

2.虚拟模式的Windows窗体DataGridView控件

事件,使控制查找数据缓存中的值。

绑定模式和虚拟模式

 

产权和控制自动加载数据从指定源和提交用户更改回去。 您可以控制显示哪些列绑定的,和数据源本身通常处理操作,如排序。

补充绑定模式

 

可以补充绑定模式通过显示的列的列。 这是有时被称为“混合模式”,是用于显示诸如计算值或用户界面(UI)控件。

控制与之交互。

类引用主题。

更换绑定模式

 

如果绑定模式不能满足您的性能需求,您可以通过虚拟方式管理你所有的数据在一个自定义缓存事件处理程序。 例如,您可以使用虚拟模式来实现即时数据加载机制,从网络数据库检索只有尽可能多的数据作为最优性能是必要的。 这个场景是特别有用的在处理大量数据时在一个缓慢的网络连接或与客户端机器的数量有限的内存或者存储空间。

虚拟方式事件

 

事件可能是唯一事件需要处理。 额外的虚拟方式事件让你使特定功能用户编辑、添加和删除行,行级的事务。

事件(如当用户添加或删除行发生的事件,或当细胞值编辑,解析,验证,或格式化的)是有用的在虚拟模式,。 你也可以处理事件,让你保持值不是通常存储在一个绑定数据源,如细胞提示文本,细胞和行错误文本,细胞和行快捷菜单数据,和行高数据。

属性引用主题。

 

事件

描述

CellValueNeeded

控制使用的检索数据缓存的一个细胞值显示。 这个事件只发生在未绑定列细胞。

CellValuePushed

使用的控制提交用户输入一个细胞到数据缓存。 这个事件只发生在未绑定列细胞。

事件处理程序,以确保当前值显示在控制和自动分级模式目前在应用任何效果。

NewRowNeeded

使用的控制来表示数据缓存需要一个新行。

RowDirtyStateNeeded

连续使用的控制,以确定任何未提交的更改。

CancelRowEdit

控制用于显示一行应该回归其缓存值。

属性设置。

 

事件

描述

UserDeletingRow

UserDeletedRow

RowsRemoved

RowsAdded

使用的控制指示当行被删除或添加,让你更新相应数据缓存。

CellFormatting

CellParsing

CellValidating

CellValidated

RowValidating

RowValidated

使用的控制格式的单元格值显示,解析和验证用户输入。

CellToolTipTextNeeded

CellErrorTextNeeded

RowErrorTextNeeded

方法当你改变细胞或行错误文本,以确保当前值显示在控制。

CellContextMenuStripNeeded

RowContextMenuStripNeeded

RowHeightInfoNeeded

RowHeightInfoPushed

事件处理程序,以确保当前值的显示控制。

3.介绍:在Windows窗体DataGridView控件中实现虚拟模式

和显式地管理控制的交互数据存储。 这允许您调整控制在这种情况下的性能。

事件进行交互和更新缓存。 有关更多信息,请参见 实现虚拟模式的即时数据加载Windows窗体DataGridView控件

创建表单

 

实现虚拟模式

  1. 控制。

    方法,并提供了一个简单的表单布局在类的构造函数。

using System;
using System.Windows.Forms;

public class Form1 : Form
{
    private DataGridView dataGridView1 = new DataGridView();

    // Declare an ArrayList to serve as the data store.  
    private System.Collections.ArrayList customers =
        new System.Collections.ArrayList();

    // Declare a Customer object to store data for a row being edited. 
    private Customer customerInEdit;

    // Declare a variable to store the index of a row being edited.  
    // A value of -1 indicates that there is no row currently in edit.  
    private int rowInEdit = -1;

    // Declare a variable to indicate the commit scope.  
    // Set this value to false to use cell-level commit scope.  
    private bool rowScopeCommit = true;

    [STAThreadAttribute()]
    public static void Main()
    {
        Application.Run(new Form1());
    }

    public Form1()
    {
        // Initialize the form. 
        this.dataGridView1.Dock = DockStyle.Fill;
        this.Controls.Add(this.dataGridView1);
        this.Load += new EventHandler(Form1_Load);
        this.Text = "DataGridView virtual-mode demo (row-level commit scope)";
    }


...


}
View Code

控制和填充数据存储与样本值。

private void Form1_Load(object sender, EventArgs e)
{
    // Enable virtual mode. 
    this.dataGridView1.VirtualMode = true;

    // Connect the virtual-mode events to event handlers.  
    this.dataGridView1.CellValueNeeded += new
        DataGridViewCellValueEventHandler(dataGridView1_CellValueNeeded);
    this.dataGridView1.CellValuePushed += new
        DataGridViewCellValueEventHandler(dataGridView1_CellValuePushed);
    this.dataGridView1.NewRowNeeded += new
        DataGridViewRowEventHandler(dataGridView1_NewRowNeeded);
    this.dataGridView1.RowValidated += new
        DataGridViewCellEventHandler(dataGridView1_RowValidated);
    this.dataGridView1.RowDirtyStateNeeded += new
        QuestionEventHandler(dataGridView1_RowDirtyStateNeeded);
    this.dataGridView1.CancelRowEdit += new
        QuestionEventHandler(dataGridView1_CancelRowEdit);
    this.dataGridView1.UserDeletingRow += new
        DataGridViewRowCancelEventHandler(dataGridView1_UserDeletingRow);

    // Add columns to the DataGridView.
    DataGridViewTextBoxColumn companyNameColumn = new
        DataGridViewTextBoxColumn();
    companyNameColumn.HeaderText = "Company Name";
    companyNameColumn.Name = "Company Name";
    DataGridViewTextBoxColumn contactNameColumn = new
        DataGridViewTextBoxColumn();
    contactNameColumn.HeaderText = "Contact Name";
    contactNameColumn.Name = "Contact Name";
    this.dataGridView1.Columns.Add(companyNameColumn);
    this.dataGridView1.Columns.Add(contactNameColumn);
    this.dataGridView1.AutoSizeColumnsMode = 
        DataGridViewAutoSizeColumnsMode.AllCells;

    // Add some sample entries to the data store.  
    this.customers.Add(new Customer(
        "Bon app'", "Laurence Lebihan"));
    this.customers.Add(new Customer(
        "Bottom-Dollar Markets", "Elizabeth Lincoln"));
    this.customers.Add(new Customer(
        "B's Beverages", "Victoria Ashworth"));

    // Set the row count, including the row for new records. 
    this.dataGridView1.RowCount = 4;
}
View Code

当前在编辑对象。

控制细胞需要油漆。

private void dataGridView1_CellValueNeeded(object sender,
    System.Windows.Forms.DataGridViewCellValueEventArgs e)
{
    // If this is the row for new records, no values are needed. 
    if (e.RowIndex == this.dataGridView1.RowCount - 1) return;

    Customer customerTmp = null;

    // Store a reference to the Customer object for the row being painted. 
    if (e.RowIndex == rowInEdit)
    {
        customerTmp = this.customerInEdit;
    }
    else 
    {
        customerTmp = (Customer)this.customers[e.RowIndex];
    }

    // Set the cell value to paint using the Customer object retrieved. 
    switch (this.dataGridView1.Columns[e.ColumnIndex].Name)
    {
        case "Company Name":
            e.Value = customerTmp.CompanyName;
            break;

        case "Contact Name":
            e.Value = customerTmp.ContactName;
            break;
    }
}
View Code

4.对象代表行进行编辑。 这个事件发生时只要用户提交一个细胞值变化。

private void dataGridView1_CellValuePushed(object sender,
    System.Windows.Forms.DataGridViewCellValueEventArgs e)
{
    Customer customerTmp = null;

    // Store a reference to the Customer object for the row being edited. 
    if (e.RowIndex < this.customers.Count)
    {
        // If the user is editing a new row, create a new Customer object. 
        if (this.customerInEdit == null)
        {
            this.customerInEdit = new Customer(
                ((Customer)this.customers[e.RowIndex]).CompanyName,
                ((Customer)this.customers[e.RowIndex]).ContactName);
        }
        customerTmp = this.customerInEdit;
        this.rowInEdit = e.RowIndex;
    }
    else
    {
        customerTmp = this.customerInEdit;
    }

    // Set the appropriate Customer property to the cell value entered.
    String newValue = e.Value as String;
    switch (this.dataGridView1.Columns[e.ColumnIndex].Name)
    {
        case "Company Name":
            customerTmp.CompanyName = newValue;
            break;

        case "Contact Name":
            customerTmp.ContactName = newValue;
            break;
    }
}
View Code

5. 对象代表一个新创建的行。

这个事件发生时用户输入新记录的行。

private void dataGridView1_NewRowNeeded(object sender,
    System.Windows.Forms.DataGridViewRowEventArgs e)
{
    // Create a new Customer object when the user edits 
    // the row for new records. 
    this.customerInEdit = new Customer();
    this.rowInEdit = this.dataGridView1.Rows.Count - 1;
}
View Code

6. 事件,保存新的或修改的行数据存储。

这个事件发生时用户更改当前行。

private void dataGridView1_RowValidated(object sender,
    System.Windows.Forms.DataGridViewCellEventArgs e)
{
    // Save row changes if any were made and release the edited  
    // Customer object if there is one. 
    if (e.RowIndex >= this.customers.Count &&
        e.RowIndex != this.dataGridView1.Rows.Count - 1)
    {
        // Add the new Customer object to the data store. 
        this.customers.Add(this.customerInEdit);
        this.customerInEdit = null;
        this.rowInEdit = -1;
    }
    else if (this.customerInEdit != null &&
        e.RowIndex < this.customers.Count)
    {
        // Save the modified Customer object in the data store. 
        this.customers[e.RowIndex] = this.customerInEdit;
        this.customerInEdit = null;
        this.rowInEdit = -1;
    }
    else if (this.dataGridView1.ContainsFocus)
    {
        this.customerInEdit = null;
        this.rowInEdit = -1;
    }
}
View Code

7. 事件将发生,当用户信号连续降级在编辑模式下按下ESC两次或一次以外的编辑模式。

事件处理程序。 这个事件非常有用当提交范围是在运行时确定的。

private void dataGridView1_RowDirtyStateNeeded(object sender,
    System.Windows.Forms.QuestionEventArgs e)
{
    if (!rowScopeCommit)
    {
        // In cell-level commit scope, indicate whether the value 
        // of the current cell has been modified.
        e.Response = this.dataGridView1.IsCurrentCellDirty;
    }
}
View Code

对象代表当前行。

事件处理程序。

private void dataGridView1_CancelRowEdit(object sender,
    System.Windows.Forms.QuestionEventArgs e)
{
    if (this.rowInEdit == this.dataGridView1.Rows.Count - 2 &&
        this.rowInEdit == this.customers.Count)
    {
        // If the user has canceled the edit of a newly created row,  
        // replace the corresponding Customer object with a new, empty one. 
        this.customerInEdit = new Customer();
    }
    else
    {
        // If the user has canceled the edit of an existing row,  
        // release the corresponding Customer object. 
        this.customerInEdit = null;
        this.rowInEdit = -1;
    }
}
View Code

9.

对象代表一个新创建的行。

这事件发生时每当用户点击一行删除一行标题,按删除键。

private void dataGridView1_UserDeletingRow(object sender,
    System.Windows.Forms.DataGridViewRowCancelEventArgs e)
{
    if (e.Row.Index < this.customers.Count)
    {
        // If the user has deleted an existing row, remove the  
        // corresponding Customer object from the data store. 
        this.customers.RemoveAt(e.Row.Index);
    }

    if (e.Row.Index == this.rowInEdit)
    {
        // If the user has deleted a newly created row, release 
        // the corresponding Customer object.  
        this.rowInEdit = -1;
        this.customerInEdit = null;
    }
}
View Code

10.类来代表这段代码示例所使用的数据项。

public class Customer
{
    private String companyNameValue;
    private String contactNameValue;

    public Customer()
    {
        // Leave fields empty.
    }

    public Customer(String companyName, String contactName)
    {
        companyNameValue = companyName;
        contactNameValue = contactName;
    }

    public String CompanyName
    {
        get
        {
            return companyNameValue;
        }
        set
        {
            companyNameValue = value;
        }
    }

    public String ContactName
    {
        get
        {
            return contactNameValue;
        }
        set
        {
            contactNameValue = value;
        }
    }
}
View Code

测试应用程序

 

您现在可以测试形式,以确保它的行为。

测试表单

  • 编译并运行应用程序。

    对象数据存储的修改、添加或删除。

最佳实践扩展Windows窗体DataGridView控件 .net 4.5 附示例代码
 
1.最佳实践扩展Windows窗体DataGridView控件
2.虚拟模式的Windows窗体DataGridView控件
3.介绍:在Windows窗体DataGridView控件中实现虚拟模式
4.如何:实现虚拟模式的即时数据加载Windows窗体DataGridView控制

下一个步骤

 

控制。 你可以改善这个基本的应用程序在许多方面:

  • 实现一个数据存储,从外部数据库缓存值。 缓存应该必要的检索和丢弃的值,以便显示只包含什么是必要的同时消耗少量的内存在客户端计算机。

  • 调整数据存储的性能取决于您的需求。 例如,您可能想要弥补缓慢的网络连接,而不是端计算机内存限制通过使用一个更大的缓存大小和最小化数据库查询的数量。

4.如何:实现虚拟模式的即时数据加载Windows窗体DataGridView控制

  1 using System;
  2 using System.Data;
  3 using System.Data.SqlClient;
  4 using System.Drawing;
  5 using System.Windows.Forms;
  6 
  7 public class VirtualJustInTimeDemo : System.Windows.Forms.Form
  8 {
  9     private DataGridView dataGridView1 = new DataGridView();
 10     private Cache memoryCache;
 11 
 12     // Specify a connection string. Replace the given value with a  
 13     // valid connection string for a Northwind SQL Server sample 
 14     // database accessible to your system. 
 15     private string connectionString =
 16         "Initial Catalog=NorthWind;Data Source=localhost;" +
 17         "Integrated Security=SSPI;Persist Security Info=False";
 18     private string table = "Orders";
 19 
 20     protected override void OnLoad(EventArgs e)
 21     {
 22         // Initialize the form. 
 23         this.AutoSize = true;
 24         this.Controls.Add(this.dataGridView1);
 25         this.Text = "DataGridView virtual-mode just-in-time demo";
 26 
 27         // Complete the initialization of the DataGridView. 
 28         this.dataGridView1.Size = new Size(800, 250);
 29         this.dataGridView1.Dock = DockStyle.Fill;
 30         this.dataGridView1.VirtualMode = true;
 31         this.dataGridView1.ReadOnly = true;
 32         this.dataGridView1.AllowUserToAddRows = false;
 33         this.dataGridView1.AllowUserToOrderColumns = false;
 34         this.dataGridView1.SelectionMode =
 35             DataGridViewSelectionMode.FullRowSelect;
 36         this.dataGridView1.CellValueNeeded += new
 37             DataGridViewCellValueEventHandler(dataGridView1_CellValueNeeded);
 38 
 39         // Create a DataRetriever and use it to create a Cache object 
 40         // and to initialize the DataGridView columns and rows. 
 41         try
 42         {
 43             DataRetriever retriever =
 44                 new DataRetriever(connectionString, table);
 45             memoryCache = new Cache(retriever, 16);
 46             foreach (DataColumn column in retriever.Columns)
 47             {
 48                 dataGridView1.Columns.Add(
 49                     column.ColumnName, column.ColumnName);
 50             }
 51             this.dataGridView1.RowCount = retriever.RowCount;
 52         }
 53         catch (SqlException)
 54         {
 55             MessageBox.Show("Connection could not be established. " +
 56                 "Verify that the connection string is valid.");
 57             Application.Exit();
 58         }
 59 
 60         // Adjust the column widths based on the displayed values. 
 61         this.dataGridView1.AutoResizeColumns(
 62             DataGridViewAutoSizeColumnsMode.DisplayedCells);
 63 
 64         base.OnLoad(e);
 65     }
 66 
 67     private void dataGridView1_CellValueNeeded(object sender,
 68         DataGridViewCellValueEventArgs e)
 69     {
 70         e.Value = memoryCache.RetrieveElement(e.RowIndex, e.ColumnIndex);
 71     }
 72 
 73     [STAThreadAttribute()]
 74     public static void Main()
 75     {
 76         Application.Run(new VirtualJustInTimeDemo());
 77     }
 78 
 79 }
 80 
 81 public interface IDataPageRetriever
 82 {
 83     DataTable SupplyPageOfData(int lowerPageBoundary, int rowsPerPage);
 84 }
 85 
 86 public class DataRetriever : IDataPageRetriever
 87 {
 88     private string tableName;
 89     private SqlCommand command;
 90 
 91     public DataRetriever(string connectionString, string tableName)
 92     {
 93         SqlConnection connection = new SqlConnection(connectionString);
 94         connection.Open();
 95         command = connection.CreateCommand();
 96         this.tableName = tableName;
 97     }
 98 
 99     private int rowCountValue = -1;
100 
101     public int RowCount
102     {
103         get
104         {
105             // Return the existing value if it has already been determined. 
106             if (rowCountValue != -1)
107             {
108                 return rowCountValue;
109             }
110 
111             // Retrieve the row count from the database.
112             command.CommandText = "SELECT COUNT(*) FROM " + tableName;
113             rowCountValue = (int)command.ExecuteScalar();
114             return rowCountValue;
115         }
116     }
117 
118     private DataColumnCollection columnsValue;
119 
120     public DataColumnCollection Columns
121     {
122         get
123         {
124             // Return the existing value if it has already been determined. 
125             if (columnsValue != null)
126             {
127                 return columnsValue;
128             }
129 
130             // Retrieve the column information from the database.
131             command.CommandText = "SELECT * FROM " + tableName;
132             SqlDataAdapter adapter = new SqlDataAdapter();
133             adapter.SelectCommand = command;
134             DataTable table = new DataTable();
135             table.Locale = System.Globalization.CultureInfo.InvariantCulture;
136             adapter.FillSchema(table, SchemaType.Source);
137             columnsValue = table.Columns;
138             return columnsValue;
139         }
140     }
141 
142     private string commaSeparatedListOfColumnNamesValue = null;
143 
144     private string CommaSeparatedListOfColumnNames
145     {
146         get
147         {
148             // Return the existing value if it has already been determined. 
149             if (commaSeparatedListOfColumnNamesValue != null)
150             {
151                 return commaSeparatedListOfColumnNamesValue;
152             }
153 
154             // Store a list of column names for use in the 
155             // SupplyPageOfData method.
156             System.Text.StringBuilder commaSeparatedColumnNames =
157                 new System.Text.StringBuilder();
158             bool firstColumn = true;
159             foreach (DataColumn column in Columns)
160             {
161                 if (!firstColumn)
162                 {
163                     commaSeparatedColumnNames.Append(", ");
164                 }
165                 commaSeparatedColumnNames.Append(column.ColumnName);
166                 firstColumn = false;
167             }
168 
169             commaSeparatedListOfColumnNamesValue =
170                 commaSeparatedColumnNames.ToString();
171             return commaSeparatedListOfColumnNamesValue;
172         }
173     }
174 
175     // Declare variables to be reused by the SupplyPageOfData method. 
176     private string columnToSortBy;
177     private SqlDataAdapter adapter = new SqlDataAdapter();
178 
179     public DataTable SupplyPageOfData(int lowerPageBoundary, int rowsPerPage)
180     {
181         // Store the name of the ID column. This column must contain unique  
182         // values so the SQL below will work properly. 
183         if (columnToSortBy == null)
184         {
185             columnToSortBy = this.Columns[0].ColumnName;
186         }
187 
188         if (!this.Columns[columnToSortBy].Unique)
189         {
190             throw new InvalidOperationException(String.Format(
191                 "Column {0} must contain unique values.", columnToSortBy));
192         }
193 
194         // Retrieve the specified number of rows from the database, starting 
195         // with the row specified by the lowerPageBoundary parameter.
196         command.CommandText = "Select Top " + rowsPerPage + " " +
197             CommaSeparatedListOfColumnNames + " From " + tableName +
198             " WHERE " + columnToSortBy + " NOT IN (SELECT TOP " +
199             lowerPageBoundary + " " + columnToSortBy + " From " +
200             tableName + " Order By " + columnToSortBy +
201             ") Order By " + columnToSortBy;
202         adapter.SelectCommand = command;
203 
204         DataTable table = new DataTable();
205         table.Locale = System.Globalization.CultureInfo.InvariantCulture;
206         adapter.Fill(table);
207         return table;
208     }
209 
210 }
211 
212 public class Cache
213 {
214     private static int RowsPerPage;
215 
216     // Represents one page of data.   
217     public struct DataPage
218     {
219         public DataTable table;
220         private int lowestIndexValue;
221         private int highestIndexValue;
222 
223         public DataPage(DataTable table, int rowIndex)
224         {
225             this.table = table;
226             lowestIndexValue = MapToLowerBoundary(rowIndex);
227             highestIndexValue = MapToUpperBoundary(rowIndex);
228             System.Diagnostics.Debug.Assert(lowestIndexValue >= 0);
229             System.Diagnostics.Debug.Assert(highestIndexValue >= 0);
230         }
231 
232         public int LowestIndex
233         {
234             get
235             {
236                 return lowestIndexValue;
237             }
238         }
239 
240         public int HighestIndex
241         {
242             get
243             {
244                 return highestIndexValue;
245             }
246         }
247 
248         public static int MapToLowerBoundary(int rowIndex)
249         {
250             // Return the lowest index of a page containing the given index. 
251             return (rowIndex / RowsPerPage) * RowsPerPage;
252         }
253 
254         private static int MapToUpperBoundary(int rowIndex)
255         {
256             // Return the highest index of a page containing the given index. 
257             return MapToLowerBoundary(rowIndex) + RowsPerPage - 1;
258         }
259     }
260 
261     private DataPage[] cachePages;
262     private IDataPageRetriever dataSupply;
263 
264     public Cache(IDataPageRetriever dataSupplier, int rowsPerPage)
265     {
266         dataSupply = dataSupplier;
267         Cache.RowsPerPage = rowsPerPage;
268         LoadFirstTwoPages();
269     }
270 
271     // Sets the value of the element parameter if the value is in the cache. 
272     private bool IfPageCached_ThenSetElement(int rowIndex,
273         int columnIndex, ref string element)
274     {
275         if (IsRowCachedInPage(0, rowIndex))
276         {
277             element = cachePages[0].table
278                 .Rows[rowIndex % RowsPerPage][columnIndex].ToString();
279             return true;
280         }
281         else if (IsRowCachedInPage(1, rowIndex))
282         {
283             element = cachePages[1].table
284                 .Rows[rowIndex % RowsPerPage][columnIndex].ToString();
285             return true;
286         }
287 
288         return false;
289     }
290 
291     public string RetrieveElement(int rowIndex, int columnIndex)
292     {
293         string element = null;
294 
295         if (IfPageCached_ThenSetElement(rowIndex, columnIndex, ref element))
296         {
297             return element;
298         }
299         else
300         {
301             return RetrieveData_CacheIt_ThenReturnElement(
302                 rowIndex, columnIndex);
303         }
304     }
305 
306     private void LoadFirstTwoPages()
307     {
308         cachePages = new DataPage[]{
309             new DataPage(dataSupply.SupplyPageOfData(
310                 DataPage.MapToLowerBoundary(0), RowsPerPage), 0), 
311             new DataPage(dataSupply.SupplyPageOfData(
312                 DataPage.MapToLowerBoundary(RowsPerPage), 
313                 RowsPerPage), RowsPerPage)};
314     }
315 
316     private string RetrieveData_CacheIt_ThenReturnElement(
317         int rowIndex, int columnIndex)
318     {
319         // Retrieve a page worth of data containing the requested value.
320         DataTable table = dataSupply.SupplyPageOfData(
321             DataPage.MapToLowerBoundary(rowIndex), RowsPerPage);
322 
323         // Replace the cached page furthest from the requested cell 
324         // with a new page containing the newly retrieved data.
325         cachePages[GetIndexToUnusedPage(rowIndex)] = new DataPage(table, rowIndex);
326 
327         return RetrieveElement(rowIndex, columnIndex);
328     }
329 
330     // Returns the index of the cached page most distant from the given index 
331     // and therefore least likely to be reused. 
332     private int GetIndexToUnusedPage(int rowIndex)
333     {
334         if (rowIndex > cachePages[0].HighestIndex &&
335             rowIndex > cachePages[1].HighestIndex)
336         {
337             int offsetFromPage0 = rowIndex - cachePages[0].HighestIndex;
338             int offsetFromPage1 = rowIndex - cachePages[1].HighestIndex;
339             if (offsetFromPage0 < offsetFromPage1)
340             {
341                 return 1;
342             }
343             return 0;
344         }
345         else
346         {
347             int offsetFromPage0 = cachePages[0].LowestIndex - rowIndex;
348             int offsetFromPage1 = cachePages[1].LowestIndex - rowIndex;
349             if (offsetFromPage0 < offsetFromPage1)
350             {
351                 return 1;
352             }
353             return 0;
354         }
355 
356     }
357 
358     // Returns a value indicating whether the given row index is contained 
359     // in the given DataPage.  
360     private bool IsRowCachedInPage(int pageNumber, int rowIndex)
361     {
362         return rowIndex <= cachePages[pageNumber].HighestIndex &&
363             rowIndex >= cachePages[pageNumber].LowestIndex;
364     }
365 
366 }
VirtualJustInTimeDemo

编译的代码

这个示例需要:
  • 引用到系统,系统。 数据系统。 Xml和System.Windows。 表单组件。

  • 访问服务器与罗斯文SQL server安装的示例数据库。

  • 运行如图

最佳实践扩展Windows窗体DataGridView控件 .net 4.5 附示例代码
 
1.最佳实践扩展Windows窗体DataGridView控件
2.虚拟模式的Windows窗体DataGridView控件
3.介绍:在Windows窗体DataGridView控件中实现虚拟模式
4.如何:实现虚拟模式的即时数据加载Windows窗体DataGridView控制

本文地址:http://www.cnblogs.com/endv/p/4234537.html

官方地址:http://msdn.microsoft.com/en-us/library/ms171621.aspx

译者Q:77811970

源代码下载:http://files.cnblogs.com/endv/DataGridViewFrom.rar 点击