DataGridView的虛擬模式,允許我們?cè)谛枰獣r(shí)再檢索數(shù)據(jù)。達(dá)到實(shí)時(shí)加載的目的。這避免了DataGridView由于大數(shù)據(jù)量而刷新延遲,也避免了數(shù)據(jù)量過大造成網(wǎng)絡(luò)超時(shí),更可以節(jié)約本地內(nèi)存??傊?,它的好處多多,但是要實(shí)現(xiàn)這種方式,需要做的事情可不是那么簡單,所以需要權(quán)衡項(xiàng)目中是否有這樣的大數(shù)據(jù)。
基本思路就是:
1,本地設(shè)立數(shù)據(jù)的緩存。比如裝載100條數(shù)據(jù)。
2,如果用戶查閱的數(shù)據(jù)超過了這個(gè)數(shù),就去取下100條數(shù)據(jù),并可以考慮丟掉前面的一些緩存,以保證本地內(nèi)存不會(huì)太大。
3,如何判斷是否應(yīng)該去取數(shù)據(jù),DataGridView已經(jīng)提供了相應(yīng)的一些事件,如:CellValueNeeded,一般以XXXNeeded的事件就是告訴你需要取數(shù)據(jù)了。當(dāng)然,一個(gè)重要的前提是要開啟DataGridView的虛擬模式,這些事件才會(huì)有效。this.dataGridView1.VirtualMode = true;在這些事件里,我們可以對(duì)DataGridView的單元格賦值(就是直接取緩存的數(shù)據(jù)來顯示,緩存里如果沒有,會(huì)自動(dòng)去取下100條數(shù)據(jù))。
4,取下100條數(shù)據(jù),可能要涉及到SQL的分頁。比如用top 100 等就可以簡單實(shí)現(xiàn)。
下面的例子就是一個(gè)緩存的例子,照著MSDN做的,可以做個(gè)參考。即使不用于DataGridView,這個(gè)緩存的思想也是非常值得借鑒的。
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace DataGridViewVirtualModeTest
{
interface IDataPageRetriever
{
DataTable ApplyPageOfData(int lowPageBoundary, int rowsPerPage);
}
internal class DataRetriever : IDataPageRetriever
{
private const String Conn_Str =
@"Data Source=SK-WZ\SQLEXPRESS;Initial Catalog=TestUse;Persist Security Info=True;User ID=wang;password=wang";
private string tableName;
private SqlCommand command;
public DataRetriever(string tableName)
{
this.tableName = tableName;
SqlConnection conn = new SqlConnection(Conn_Str);
conn.Open();
command = conn.CreateCommand();
}
private int rowCount = -1;
public int RowCount
{
get
{
if (rowCount != -1)
return RowCount;
command.CommandText = "select count(*) from " + tableName;
rowCount = (int)command.ExecuteScalar();
return rowCount;
}
}
private DataColumnCollection columns;
public DataColumnCollection Columns
{
get
{
if (columns != null)
return columns;
command.CommandText = "select * from " + tableName;
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = command;
DataTable table = new DataTable();
table.Locale = System.Globalization.CultureInfo.CurrentCulture;
adapter.FillSchema(table, SchemaType.Source);
columns = table.Columns;
return columns;
}
}
private string commaSeparatedColumnNames;
public string CommaSeparatedColumnNames
{
get
{
if (commaSeparatedColumnNames != null)
return commaSeparatedColumnNames;
StringBuilder builder = new StringBuilder();
bool isFirstColumn = true;
foreach (DataColumn column in Columns)
{
if (!isFirstColumn)
{
builder.Append(",");
}
isFirstColumn = false;
builder.Append(column.ColumnName);
}
commaSeparatedColumnNames = builder.ToString();
return commaSeparatedColumnNames;
}
}
#region IDataPageRetriver
private string keyColumnName;
public DataTable ApplyPageOfData(int lowPageBoundary, int rowsPerPage)
{
keyColumnName = Columns[0].ColumnName;
StringBuilder builder = new StringBuilder();
builder.Append(" select top " + rowsPerPage + " " + CommaSeparatedColumnNames + " from ");
builder.Append(tableName);
builder.Append(" where " + keyColumnName + " not in (");
builder.Append(" select top " + lowPageBoundary + " " + keyColumnName);
builder.Append(" from " + tableName + " order by " + keyColumnName + ") ");
builder.Append(" order by " + keyColumnName);
command.CommandText = builder.ToString();
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = command;
DataTable table = new DataTable();
adapter.Fill(table);
return table;
}
#endregion
}
internal class Cache
{
private struct DataPage
{
public DataTable table;
private int lowIndex;
private int highIndex;
public DataPage(DataTable table, int rowIndex)
{
this.table = table;
this.lowIndex = MapLowerBoundary(rowIndex);
this.highIndex = MapUpperBoundary(rowIndex);
}
public int LowIndex
{
get { return this.lowIndex; }
}
public int HighIndex
{
get { return this.highIndex; }
}
public static int MapLowerBoundary(int rowIndex)
{
return (rowIndex / RowPerPage) * RowPerPage;
}
public static int MapUpperBoundary(int rowIndex)
{
return MapLowerBoundary(rowIndex) + RowPerPage - 1;
}
}
IDataPageRetriever dataSupply;
static int RowPerPage;
DataPage[] catchPages = new DataPage[2];
public Cache(IDataPageRetriever dataSupplier, int rowsPerPage)
{
this.dataSupply = dataSupplier;
RowPerPage = rowsPerPage;
PreLoadDataPages();
}
private void PreLoadDataPages()
{
catchPages[0] = new DataPage(dataSupply.ApplyPageOfData(0, RowPerPage), 0);
catchPages[1] = new DataPage(dataSupply.ApplyPageOfData(RowPerPage, RowPerPage), RowPerPage);
}
public string RetrieveElement(int rowIndex, int colIndex)
{
string element = "";
if (IfPageCatched_TheSetElement(rowIndex, colIndex, ref element))
{
return element;
}
else
{
element = RetrieveData_CatchIt_ReturnElement(rowIndex, colIndex);
}
return element;
}
private bool IfPageCatched_TheSetElement(int rowIndex, int colIndex, ref string element)
{
if (IsRowCatchedInPage(0, rowIndex))
{
element = catchPages[0].table.Rows[rowIndex % RowPerPage][colIndex].ToString();
return true;
}
else if (IsRowCatchedInPage(1, rowIndex))
{
element = catchPages[1].table.Rows[rowIndex % RowPerPage][colIndex].ToString();
return true;
}
return false;
}
private string RetrieveData_CatchIt_ReturnElement(int rowIndex, int colIndex)
{
DataPage newPage = new DataPage(dataSupply.ApplyPageOfData(DataPage.MapLowerBoundary(rowIndex), RowPerPage), rowIndex);
//which old datapage should be replaced?
catchPages[GetIndexOfReplacedPage(rowIndex)] = newPage;
return RetrieveElement(rowIndex, colIndex);
}
private bool IsRowCatchedInPage(int pageNum, int rowIndex)
{
return catchPages[pageNum].LowIndex <= rowIndex &&
catchPages[pageNum].HighIndex >= rowIndex;
}
private int GetIndexOfReplacedPage(int rowIndex)
{
if (catchPages[0].HighIndex < rowIndex && catchPages[1].HighIndex < rowIndex)
{
int offsetFromPage0 = rowIndex - catchPages[0].HighIndex;
int offsetFromPage1 = rowIndex - catchPages[1].HighIndex;
if (offsetFromPage0 < offsetFromPage1)
return 1;
else
return 0;
}
else
{
int offsetFromPage0 = catchPages[0].LowIndex - rowIndex;
int offsetFromPage1 = catchPages[1].LowIndex - rowIndex;
if (offsetFromPage0 < offsetFromPage1)
return 1;
return 0;
}
}
}
}
DataGridView調(diào)用
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace DataGridViewVirtualModeTest
{
public partial class Form1 : Form
{
Cache memoryCache;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
DataRetriever dataSupply = new DataRetriever("t_temp");
memoryCache = new Cache(dataSupply, 50);
foreach (DataColumn column in dataSupply.Columns)
{
this.dataGridView1.Columns.Add(column.ColumnName, column.ColumnName);
}
this.dataGridView1.RowCount = dataSupply.RowCount;
this.dataGridView1.VirtualMode = true;
this.dataGridView1.ReadOnly = true;
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView1.AllowUserToOrderColumns = false;
this.dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
this.dataGridView1.CellValueNeeded += new DataGridViewCellValueEventHandler(dataGridView1_CellValueNeeded);
this.dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;
}
void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
e.Value = memoryCache.RetrieveElement(e.RowIndex, e.ColumnIndex);
}
}
}
文章內(nèi)容來自網(wǎng)絡(luò),僅用于學(xué)習(xí)交流,版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員刪除。