最佳實踐擴充套件Windows窗體DataGridView控制元件 .net 4.5 附示例程式碼

Endv發表於2015-01-19

Windows窗體DataGridView控制元件效能調優.net 4.5

 

 

在處理大量資料時, DataGridView 控制可以消耗大量的記憶體開銷,除非你仔細地使用它。 在客戶有限的記憶體,你可以避免一些這方面的開銷,避免記憶體成本高的特性。 你也可以管理的部分或全部資料維護和檢索任務自己使用虛擬模式為了定製的記憶體使用情況。

在這一節中

 
最佳實踐擴充套件Windows窗體DataGridView控制元件

描述如何使用 DataGridView 控制,避免了不必要的記憶體使用和在處理大量資料時的效能損失。

虛擬模式的Windows窗體DataGridView控制元件

描述如何使用虛擬模式來補充或替換標準的資料繫結機制。

介紹:在Windows窗體DataGridView控制元件中實現虛擬模式

描述如何實現事件處理程式幾個虛擬方式。 還演示瞭如何實現行級回滾併為使用者編輯提交。

實現虛擬模式的即時資料載入Windows窗體DataGridView控制元件

描述如何載入資料的需求,這是非常有用的,當你有更多的資料比可用來顯示客戶端記憶體可以儲存。

 

1.最佳實踐擴充套件Windows窗體DataGridView控制元件

.net 4.5
 
 

 DataGridView 控制的目的是提供最大的可伸縮性。 如果你需要顯示大量資料,您應該遵循的指導方針中描述這個話題避免消耗大量記憶體或有辱人格的使用者介面(UI)的響應能力。 本主題討論以下問題:

  • 有效使用單元格樣式

  • 有效使用快捷選單

  • 有效地使用自動調整

  • 使用選定的單元格、行和列的集合

  • 使用共享的行

  • 防止行成為非共享

如果你有特殊的效能需求,您可以實現虛擬模式,提供自己的資料管理操作。 有關更多資訊,請參見 資料顯示模式在Windows窗體DataGridView控制元件 

有效使用單元格樣式

 

每個單元格、行和列可以有它自己的樣式資訊。 資訊儲存在風格 DataGridViewCellStyle 物件。 建立單元格樣式物件對於許多個人DataGridView 元素可以是低效的,特別是當處理大量的資料。 為了避免影響效能,使用以下指南:

有效使用快捷選單

 

每個單元格、行和列可以有它自己的快捷選單。 快捷選單中 DataGridView 控制用 contextmenustrip 控制。 與單元格樣式物件一樣,許多個人建立快捷方式選單 DataGridView 元素將對效能造成負面影響。 為了避免這種懲罰,使用以下指南:

  • 避免建立快捷方式選單為單個細胞和行。 這包括行模板,克隆及其快捷選單當新行新增到控制。 最大的可伸縮性,只使用控制的contextmenustrip 財產為整個控制指定一個快捷選單。

  • 如果你需要多個快捷方式選單為多個行或細胞,處理 CellContextMenuStripNeeded 或 RowContextMenuStripNeeded 事件。 這些事件讓你管理自己的快捷選單物件,允許您調整效能。

有效地使用自動調整

 

行,列,可以自動調整大小和標題單元格內容更改,這樣整個細胞顯示沒有剪下的內容。 改變分級模式還可以調整行、列和標題。 確定正確的尺寸, DataGridView 控制必須檢查每個單元格的值,它必須適應。 在處理大型資料集時,這種分析可能會對效能造成負面影響的控制自動調整發生時。 為了避免效能損失,使用以下指南:

有關更多資訊,請參見 在Windows窗體DataGridView控制元件大小的選擇 

使用選定的單元格、行和列的集合

 

的 SelectedCells 不執行有效地選擇大集合。 的 SelectedRows 和 SelectedColumns 集合也可以是低效的,雖然從一個較小的程度上,因為有很多行比細胞在一個典型的少 DataGridView 控制,許多列少於行。 為了避免效能損失在處理這些集合時,使用以下指南:

使用共享的行

 

中實現高效的記憶體使用 DataGridView 控制通過共享行。 行將分享盡可能多的資訊關於他們的外觀和行為通過共享的例項DataGridViewRow 類。

可以很容易地共享行例項節省記憶體,行成為非共享。 例如,每當使用者直接與細胞相互作用,成為非共享它的行。 因為這無法避免,這一主題的指導方針是有用的只有當處理大量資料,只有當使用者將與一個相對較小的資料每次執行你的程式的一部分。

一行不能在一個共享的 DataGridView 如果它的任何細胞包含值控制。 當 DataGridView 控制元件繫結到一個外部資料來源或當你實現虛擬模式,提供自己的資料來源,細胞外的值儲存控制,而不是在細胞物件,允許行共享。

物件只能共享一行如果可以確定所有的細胞狀態的行和列的狀態包含細胞。 如果你改變一個細胞的狀態,這樣就可以不再是推斷從國家的行和列,行不能共享。

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

在繫結模式或虛擬模式,您可以為單個細胞提供工具提示和快捷選單處理 CellToolTipTextNeeded 和 CellContextMenuStripNeeded 事件。

的 DataGridView 只要控制將自動嘗試使用共享一排排被新增到 DataGridViewRowCollection 。 使用以下指南以確保行共享:

確定一行是否共享,使用 DataGridViewRowCollection 。 SharedRow 方法檢索行物件,然後檢查物件的 指數 財產。 總是有一個共享的行 指數 屬性值為1。

防止行成為非共享

 

共享行可以成為非共享的程式碼或使用者操作。 為了避免效能影響,你應該避免造成行成為非共享。 在應用程式開發期間,您可以處理的RowUnshared 事件確定當行成為非共享。 這是有用的除錯row-sharing問題時。

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

2.虛擬模式的Windows窗體DataGridView控制元件

 

使用虛擬模式,您可以管理之間的互動 DataGridView 控制和自定義資料快取。 實現虛擬模式,設定 virtualmode 財產 真正的 和處理一個或多個事件中描述的這個話題。 你通常會處理至少 CellValueNeeded 事件,使控制查詢資料快取中的值。

繫結模式和虛擬模式

 

虛擬模式是必要的,只有當你需要補充或更換繫結模式。 在繫結模式下,設定 資料來源 產權和控制自動載入資料從指定源和提交使用者更改回去。 您可以控制顯示哪些列繫結的,和資料來源本身通常處理操作,如排序。

補充繫結模式

 

可以補充繫結模式通過顯示的列的列。 這是有時被稱為“混合模式”,是用於顯示諸如計算值或使用者介面(UI)控制元件。

因為未繫結列外的資料來源,他們忽視了資料來源的排序操作。 因此,當你在混合模式啟用排序,您必須在本地快取管理的資料和實現讓虛擬模式DataGridView 控制與之互動。

關於使用虛擬模式的更多資訊維護未繫結列中的值,看到的例子 DataGridViewCheckBoxColumn 。 ThreeState 財產和System.Windows.Forms 。 DataGridViewComboBoxColumn 類引用主題。

更換繫結模式

 

如果繫結模式不能滿足您的效能需求,您可以通過虛擬方式管理你所有的資料在一個自定義快取事件處理程式。 例如,您可以使用虛擬模式來實現即時資料載入機制,從網路資料庫檢索只有儘可能多的資料作為最優效能是必要的。 這個場景是特別有用的在處理大量資料時在一個緩慢的網路連線或與客戶端機器的數量有限的記憶體或者儲存空間。

關於使用虛擬模式的更多資訊在實時的情況下,看到的 實現虛擬模式的即時資料載入Windows窗體DataGridView控制元件 

虛擬方式事件

 

如果您的資料是隻讀的, CellValueNeeded 事件可能是唯一事件需要處理。 額外的虛擬方式事件讓你使特定功能使用者編輯、新增和刪除行,行級的事務。

一些標準 DataGridView 事件(如當使用者新增或刪除行發生的事件,或當細胞值編輯,解析,驗證,或格式化的)是有用的在虛擬模式,。 你也可以處理事件,讓你保持值不是通常儲存在一個繫結資料來源,如細胞提示文字,細胞和行錯誤文字,細胞和行快捷選單資料,和行高資料。

為更多的資訊關於實現虛擬模式管理讀/寫資料行級提交範圍,明白了 介紹:在Windows窗體DataGridView控制元件中實現虛擬模式 

為例,實現了虛擬模式具有承諾範圍,看到 virtualmode 屬性引用主題。

只有當發生以下事件 virtualmode 屬性設定為 真正的 

 

事件

描述

CellValueNeeded

控制使用的檢索資料快取的一個細胞值顯示。 這個事件只發生在未繫結列細胞。

CellValuePushed

使用的控制提交使用者輸入一個細胞到資料快取。 這個事件只發生在未繫結列細胞。

呼叫 UpdateCellValue 當改變快取值之外的一個方法 CellValuePushed 事件處理程式,以確保當前值顯示在控制和自動分級模式目前在應用任何效果。

NewRowNeeded

使用的控制來表示資料快取需要一個新行。

RowDirtyStateNeeded

連續使用的控制,以確定任何未提交的更改。

CancelRowEdit

控制用於顯示一行應該回歸其快取值。

以下事件是有用的在虛擬模式,但可以不管 virtualmode 屬性設定。

 

事件

描述

UserDeletingRow

UserDeletedRow

RowsRemoved

RowsAdded

使用的控制指示當行被刪除或新增,讓你更新相應資料快取。

CellFormatting

CellParsing

CellValidating

CellValidated

RowValidating

RowValidated

使用的控制格式的單元格值顯示,解析和驗證使用者輸入。

CellToolTipTextNeeded

控制用於檢索時細胞提示文字 資料來源 屬性設定或 virtualmode 屬性是 真正的 

細胞只有當顯示工具提示 ShowCellToolTips 屬性值是 真正的 

CellErrorTextNeeded

RowErrorTextNeeded

控制檢索單元格或行錯誤使用的文字的時候 資料來源 屬性設定或 virtualmode 屬性是 真正的 

呼叫 UpdateCellErrorText 法或者 UpdateRowErrorText 方法當你改變細胞或行錯誤文字,以確保當前值顯示在控制。

細胞和行錯誤符號時顯示 ShowCellErrors 和 ShowRowErrors 屬性值是 真正的 

CellContextMenuStripNeeded

RowContextMenuStripNeeded

使用的控制來檢索一個細胞或行 contextmenustrip 當控制 資料來源 屬性設定或 virtualmode 屬性是真正的 

RowHeightInfoNeeded

RowHeightInfoPushed

使用的控制來檢索或儲存行高資訊在資料快取。 呼叫 UpdateRowHeightInfo 方法當改變快取行之外的高度資訊 RowHeightInfoPushed 事件處理程式,以確保當前值的顯示控制。

最佳實踐在虛擬模式

 

如果你是實現虛擬模式,以有效地處理大量的資料,你也想確保高效的工作 DataGridView 控制自己。 更多資訊的有效利用細胞風格,自動分級,選擇,和行共享,明白了 最佳實踐擴充套件Windows窗體DataGridView控制元件 

 

 

 

3.介紹:在Windows窗體DataGridView控制元件中實現虛擬模式

當你想要顯示非常大量的表格資料 DataGridView 控制,您可以設定 virtualmode 財產 真正的 和顯式地管理控制的互動資料儲存。 這允許您調整控制在這種情況下的效能。

的 DataGridView 控制提供了一些事件,你可以處理與自定義資料儲存互動。 這個介紹將指導您完成這些事件處理程式實現的過程。 這個話題中的程式碼示例使用一個非常簡單的資料來源出於演示目的。 在生產環境中,您通常會只行你需要顯示載入到快取中,並處理 DataGridView 事件進行互動和更新快取。 有關更多資訊,請參見 實現虛擬模式的即時資料載入Windows窗體DataGridView控制元件

複製這個主題作為一個清單中的程式碼,看看 如何:實現虛擬模式在Windows窗體DataGridView控制元件 

建立表單

 

實現虛擬模式

  1. 建立一個類,來源於 形式 幷包含一個 DataGridView 控制。

    下面的程式碼包含了一些基本的初始化。 它宣告一些變數,將在後面使用步驟,提供了一個 主要 方法,並提供了一個簡單的表單佈局在類的建構函式。

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

 

2. 實現一個表單的處理程式 負載 事件,初始化 DataGridView 控制和填充資料儲存與樣本值。

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

 

3. 實現一個處理程式 CellValueNeeded 事件,從資料儲存中檢索請求的細胞值或 客戶 當前在編輯物件。

這個事件發生時 DataGridView 控制細胞需要油漆。

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.實現一個處理程式 CellValuePushed 事件中儲存一個編輯單元格值 客戶 物件代表行進行編輯。 這個事件發生時只要使用者提交一個細胞值變化。

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. 實現一個處理程式 NewRowNeeded 建立一個新的事件 客戶 物件代表一個新建立的行。

這個事件發生時使用者輸入新記錄的行。

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. 實現一個處理程式 RowValidated 事件,儲存新的或修改的行資料儲存。

這個事件發生時使用者更改當前行。

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. 實現一個處理程式 RowDirtyStateNeeded 事件表明是否 CancelRowEdit 事件將發生,當使用者訊號連續降級在編輯模式下按下ESC兩次或一次以外的編輯模式。

預設情況下, CancelRowEdit 發生在連續降級當任何細胞已經被修改,除非在當前行 QuestionEventArgs 。 響應 屬性設定為 真正的 在 RowDirtyStateNeeded 事件處理程式。 這個事件非常有用當提交範圍是在執行時確定的。

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

 

8. 實現一個處理程式 CancelRowEdit 事件,丟棄的值 客戶 物件代表當前行。

這個事件發生在使用者訊號連續降級在編輯模式下按下ESC兩次或一次以外的編輯模式。 這個事件不發生如果沒有修改當前行細胞或者的價值 QuestionEventArgs 。 響應 屬性被設定 假 在一個RowDirtyStateNeeded 事件處理程式。

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.

實現一個處理程式 UserDeletingRow 如果刪除一個現有的 客戶 從資料儲存物件或丟棄未儲存的 客戶 物件代表一個新建立的行。

這事件發生時每當使用者點選一行刪除一行標題,按刪除鍵。

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

 

測試應用程式

 

您現在可以測試形式,以確保它的行為。

測試表單

  • 編譯並執行應用程式。

    您將看到一個 DataGridView 控制填充三個客戶記錄。 您可以修改多個單元的值並按ESC連續兩次在編輯模式以外的編輯模式,一旦恢復整個行其原始值。 當你修改、新增或刪除行控制, 客戶 物件資料儲存的修改、新增或刪除。

下一個步驟

 

這個應用程式的事件給你一個基本的瞭解,你必須處理來實現虛擬模式 DataGridView 控制。 你可以改善這個基本的應用程式在許多方面:

  • 實現一個資料儲存,從外部資料庫快取值。 快取應該必要的檢索和丟棄的值,以便顯示只包含什麼是必要的同時消耗少量的記憶體在客戶端計算機。

  • 調整資料儲存的效能取決於您的需求。 例如,您可能想要彌補緩慢的網路連線,而不是端計算機記憶體限制通過使用一個更大的快取大小和最小化資料庫查詢的數量。

關於快取值的更多資訊從外部資料庫,明白了 如何:實現虛擬模式的即時資料載入Windows窗體DataGridView控制 

 

 

 

4.如何:實現虛擬模式的即時資料載入Windows窗體DataGridView控制

以下程式碼示例展示瞭如何使用虛擬模式 DataGridView 控制與資料快取,從伺服器載入資料只有當它是必要的。 本例中詳細描述 實現虛擬模式的即時資料載入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安裝的示例資料庫。

  • 執行如圖

從命令列資訊建設這個例子對Visual Basic或Visual c#,明白了 建築從命令列(Visual Basic) 或 命令列構建與csc.exe 。 你也可以在Visual Studio構建這個例子的程式碼貼上到一個新專案。 也看到 如何:編譯和執行一個完整的Windows窗體程式碼示例使用Visual Studio 

 

本文地址: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 點選

相關文章