DataGridView是我们显示表格数据最常用的控件, 非常好用,功能强大。但是当数据量特别大时(不管是行还是列,行的影响会小一些,列的影响特别明显)直接绑定数据会占用很久的时间,并且不能响应用户的操作而造成卡顿。所以我们就需要用到动态加载,加载部分数据,当用户滚动到边界时再加载后面的一部分数据,我们控制每次加载的行或者列的数量来保证加载速度。我们以动态加载列为示例,下面示例建立了一个1000列的table,每次加载100列供当前DataGridView显示。我们已经尝试过创建10000列的table,用此示例动态显示没有任何问题。如果直接绑定要等20分钟左右才能加载出来。
完整代码如下:form上面有两个textbox用来指定行和列的数量,一个button用来create Source table. 一个DataGridView且AutoGenerateColumns=false
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
DataTable MasterTable = null;//Source table 500 row x 1000 col
int MaskSize = 50; //Load MaskSize*2 Columns every time
int MaskStart = 0; //Display columns start index
int MaskEnd = 0;//Display columns end index
//To Create Source Table, column and Row counts defined by ColCnt and RowCnt from textbox on form
private void createTableButton_Click(object sender, EventArgs e)
{
int ColCnt = int.Parse(textBox1.Text.Trim());//1000
int RowCnt = int.Parse(textBox2.Text.Trim());//500
//create master source table
MasterTable = new DataTable();
for (int c = 0; c < ColCnt; c++)
{
MasterTable.Columns.Add("C" + c.ToString(), typeof(float));
}
for(int r=0;r< RowCnt; r++)
{
DataRow dr = MasterTable.NewRow();
for (int c = 0; c < ColCnt; c++)
{
dr["C" + c.ToString()] = r * 1.0 + c*0.01;
}
MasterTable.Rows.Add(dr);
}
//initialzie datagriview by loading 0 ~ 100 columns
int LoadStart = MaskStart;
int LoadEnd = MaskSize*1;
if (LoadEnd >= MasterTable.Columns.Count - 1)
LoadEnd = MasterTable.Columns.Count - 1;
//Dynamically create dataGridview columns
for (int i = LoadStart; i <= LoadEnd; i++)
{
DataGridViewTextBoxColumn dgvc = new DataGridViewTextBoxColumn();
dgvc.DataPropertyName = MasterTable.Columns[i].ColumnName;
dgvc.HeaderText = MasterTable.Columns[i].ColumnName;
dataGridView1.Columns.Add(dgvc);
MaskEnd = i;
}
//Load subset from SourceTable
dataGridView1.DataSource = MasterTable;
}
private void Form1_Load(object sender, EventArgs e)
{
Type t = dataGridView1.GetType();
PropertyInfo pi = t.GetProperty("HorizontalScrollBar", BindingFlags.Instance | BindingFlags.NonPublic);
ScrollBar s = null;
if (pi != null)
{
s = pi.GetValue(dataGridView1, null) as ScrollBar;
}
if (s != null)
{
s.Scroll += new ScrollEventHandler(s_Scroll);
}
dataGridView1.AutoGenerateColumns = false;
}
//define horiontal dedegate functoin
void s_Scroll(object sender, ScrollEventArgs e)
{
HScrollBar HSBar = (HScrollBar)sender;
int HBarWid = HSBar.Width;
int OldValue = e.OldValue;
int NewValue = e.NewValue;
int MaxVal = HSBar.Maximum;
int ScrollVal = HSBar.Value;
StatusLabel1.Text ="Old Value:"+ OldValue.ToString() + ", New Value:"+NewValue.ToString()+ ", Scroll Value:" + ScrollVal.ToString()+", Bar Width:"+ HBarWid.ToString() + ", Max:" + MaxVal.ToString() +", Max_85:"+(0.85 * MaxVal).ToString();
//scroll to end (right) and load next 100 columns
if (NewValue > OldValue && ScrollVal + HBarWid >= MaxVal)
{
LoadDataToGridView(true);
}
//scroll to beginning (left) and load previous 100 columns
else if (NewValue < OldValue && ScrollVal <= 0)
{
LoadDataToGridView(false);
}
}
bool DataReload = false;//flag to indicate data just reloaded
void LoadDataToGridView(bool LoadRight)
{
//Load right, and not reach end of MasterSourceTable
if(LoadRight && MaskEnd != MasterTable.Columns.Count -1)
{
//clear all dataGridView columns
dataGridView1.Columns.Clear();
//define current loading start
int LoadEnd = MaskEnd + MaskSize;
if(LoadEnd> MasterTable.Columns.Count - 1)
LoadEnd = MasterTable.Columns.Count - 1;
MaskEnd = LoadEnd;
//define current loading end
int LoadStart = MaskEnd - 2 * MaskSize;
if (LoadStart < 0)
LoadStart = 0;
MaskStart = LoadStart;
//create new dataGridColumns to bind current subset of MasterDataTable
for (int i = LoadStart; i <= LoadEnd; i++)
{
DataGridViewTextBoxColumn dgvc = new DataGridViewTextBoxColumn();
dgvc.DataPropertyName = MasterTable.Columns[i].ColumnName;
dgvc.HeaderText = MasterTable.Columns[i].ColumnName;
dataGridView1.Columns.Add(dgvc);
MaskEnd = i;
}
dataGridView1.DataSource = MasterTable;
DataReload = true;
//Invalidate dataGridView to trigger re-paint, we can only set scroll bar to center in Paint() event
dataGridView1.Invalidate();
StatusLabel1.Text = "Data columns [" + LoadStart.ToString() + " ~ " + LoadEnd.ToString() + "] loaded.";
}
//Load Left, not reached beginning of MasterSourceTable
if (!LoadRight && MaskStart != 0)
{
dataGridView1.Columns.Clear();
int LoadStart = MaskStart - MaskSize;
if (LoadStart < 0)
LoadStart = 0;
MaskStart = LoadStart;
int LoadEnd = LoadStart + 2 * MaskSize;
if (LoadEnd > MasterTable.Columns.Count - 1)
LoadEnd = MasterTable.Columns.Count - 1;
MaskEnd = LoadEnd;
for (int i = LoadStart; i <= LoadEnd; i++)
{
DataGridViewTextBoxColumn dgvc = new DataGridViewTextBoxColumn();
dgvc.DataPropertyName = MasterTable.Columns[i].ColumnName;
dgvc.HeaderText = MasterTable.Columns[i].ColumnName;
dataGridView1.Columns.Add(dgvc);
MaskEnd = i;
}
dataGridView1.DataSource = MasterTable;
DataReload = true;
dataGridView1.Invalidate();
StatusLabel1.Text = "Data columns [" + LoadStart.ToString() + " ~ " + LoadEnd.ToString() + "] loaded.";
}
}
private void dataGridView1_Paint(object sender, PaintEventArgs e)
{
if(DataReload)
{
//if data just re-loaded, set scrollBar to center
DataReload = false;
dataGridView1.FirstDisplayedScrollingColumnIndex = dataGridView1.Columns.Count / 2;
}
}
}