WinForm程序虚拟分页(实时加载数据)
Windows应用程序中很少见有分页的程序
文件夹中有上万个文件的时候微软也没让用户来翻页查看列表
记事本中的文字,某个系统功能的列表也都没有分页。(Word文档是个例外)
知道web中的分页是怎么做出来的朋友一定知道winform做分页会更简单
winform程序一样也不允许用户一下子把数据库中上万条数据全部检索出来
那么怎么让winform程序即不用翻页,又能分部加载数据呢
代码如下:
一:窗体类
Code
public partial class Form1 : Form
{
private Cache memoryCache;
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
WebPager pager = InitPager();
memoryCache = new Cache(pager, 10);
dataGridView1.RowCount = pager.TotalCount;
for (int i = 1; i < memoryCache.ColumnCollenction.Count; i++)
{
dataGridView1.Columns.Add(memoryCache.ColumnCollenction[i].ColumnName, memoryCache.ColumnCollenction[i].ColumnName);
}
//为DataGridView提供自己的数据管理操作
dataGridView1.VirtualMode = true;
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView1.AllowUserToOrderColumns = false;
this.dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
// Adjust the column widths based on the displayed values.
this.dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCells);
//VirtualMode为TRUE并且需要显示新数据时发生
dataGridView1.CellValueNeeded += new DataGridViewCellValueEventHandler(dataGridView1_CellValueNeeded);
base.OnLoad(e);
}
void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
e.Value = memoryCache.RetrieveElement(e.RowIndex, e.ColumnIndex);
}
private WebPager InitPager()
{
//设置分页类
WebPager pagerData = new WebPager();
pagerData.TableName = @"T_ENTERPRISE_ENTERPRISEJOB";
pagerData.OrderStr = "order by EEJ_CREATETIME desc";
pagerData.PageSize = 10;
return pagerData;
}
}
public partial class Form1 : Form
{
private Cache memoryCache;
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
WebPager pager = InitPager();
memoryCache = new Cache(pager, 10);
dataGridView1.RowCount = pager.TotalCount;
for (int i = 1; i < memoryCache.ColumnCollenction.Count; i++)
{
dataGridView1.Columns.Add(memoryCache.ColumnCollenction[i].ColumnName, memoryCache.ColumnCollenction[i].ColumnName);
}
//为DataGridView提供自己的数据管理操作
dataGridView1.VirtualMode = true;
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView1.AllowUserToOrderColumns = false;
this.dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
// Adjust the column widths based on the displayed values.
this.dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCells);
//VirtualMode为TRUE并且需要显示新数据时发生
dataGridView1.CellValueNeeded += new DataGridViewCellValueEventHandler(dataGridView1_CellValueNeeded);
base.OnLoad(e);
}
void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
e.Value = memoryCache.RetrieveElement(e.RowIndex, e.ColumnIndex);
}
private WebPager InitPager()
{
//设置分页类
WebPager pagerData = new WebPager();
pagerData.TableName = @"T_ENTERPRISE_ENTERPRISEJOB";
pagerData.OrderStr = "order by EEJ_CREATETIME desc";
pagerData.PageSize = 10;
return pagerData;
}
}
二:Page结构
Code
public struct DataPage
{
public DataTable table;
private int lowestIndexValue;
private int highestIndexValue;
/// <summary>
/// 一页数据的结构。构造函数
/// </summary>
/// <param name="table">数据源</param>
/// <param name="rowIndex">当前行的index</param>
public DataPage(DataTable table, int rowIndex)
{
this.table = table;
lowestIndexValue = MapToLowerBoundary(rowIndex);
highestIndexValue = MapToUpperBoundary(rowIndex);
}
/// <summary>
/// 获取当前页起始行的index
/// </summary>
public int LowestIndex
{
get
{
return lowestIndexValue;
}
}
/// <summary>
/// 获取当前页的结束行的Index
/// </summary>
public int HighestIndex
{
get
{
return highestIndexValue;
}
}
/// <summary>
/// 获取起始行的index
/// </summary>
/// <param name="rowIndex"></param>
/// <returns></returns>
public static int MapToLowerBoundary(int rowIndex)
{
return (rowIndex / RowsPerPage) * RowsPerPage;
}
/// <summary>
/// 获取结束行的index
/// </summary>
/// <param name="rowIndex"></param>
/// <returns></returns>
private static int MapToUpperBoundary(int rowIndex)
{
return MapToLowerBoundary(rowIndex) + RowsPerPage - 1;
}
/// <summary>
/// 获取当前行的页码
/// </summary>
/// <param name="rowIndex"></param>
/// <returns></returns>
public static int MapCurrentPageIndex(int rowIndex)
{
int pageindex = rowIndex / RowsPerPage;
if (rowIndex % RowsPerPage > 0)
{
return ++pageindex;
}
return pageindex;
}
}
public struct DataPage
{
public DataTable table;
private int lowestIndexValue;
private int highestIndexValue;
/// <summary>
/// 一页数据的结构。构造函数
/// </summary>
/// <param name="table">数据源</param>
/// <param name="rowIndex">当前行的index</param>
public DataPage(DataTable table, int rowIndex)
{
this.table = table;
lowestIndexValue = MapToLowerBoundary(rowIndex);
highestIndexValue = MapToUpperBoundary(rowIndex);
}
/// <summary>
/// 获取当前页起始行的index
/// </summary>
public int LowestIndex
{
get
{
return lowestIndexValue;
}
}
/// <summary>
/// 获取当前页的结束行的Index
/// </summary>
public int HighestIndex
{
get
{
return highestIndexValue;
}
}
/// <summary>
/// 获取起始行的index
/// </summary>
/// <param name="rowIndex"></param>
/// <returns></returns>
public static int MapToLowerBoundary(int rowIndex)
{
return (rowIndex / RowsPerPage) * RowsPerPage;
}
/// <summary>
/// 获取结束行的index
/// </summary>
/// <param name="rowIndex"></param>
/// <returns></returns>
private static int MapToUpperBoundary(int rowIndex)
{
return MapToLowerBoundary(rowIndex) + RowsPerPage - 1;
}
/// <summary>
/// 获取当前行的页码
/// </summary>
/// <param name="rowIndex"></param>
/// <returns></returns>
public static int MapCurrentPageIndex(int rowIndex)
{
int pageindex = rowIndex / RowsPerPage;
if (rowIndex % RowsPerPage > 0)
{
return ++pageindex;
}
return pageindex;
}
}
三:WebPager数据访问类
通过访问数据库的分页存储过程获取某一页的数据
由于这个类的代码并非我写的,所以这里不在公布了
此类公开的几个字段和一个方法如下
每页显示条数 PageSize
当前显示第几页 PageIndex
共几页 PageCount
所有的条目数 TotalCount
分页的表或者实体 TableName
查询的字段 QueryFieldName
排序字段 OrderStr
查询的条件 QueryCondition
获取数据 public DataTable QuickPageData()
四:Cache类(这个类包含了Page结构的定义)
Code
private static int RowsPerPage;
private DataPage[] cachePages;
public DataColumnCollection ColumnCollenction { get; set; }
private WebPager dataSupply;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="dataSupplier">分页类</param>
/// <param name="rowsPerPage">一页几行</param>
public Cache(WebPager dataSupplier, int rowsPerPage)
{
dataSupply = dataSupplier;
Cache.RowsPerPage = rowsPerPage;
LoadFirstTwoPages();
}
/// <summary>
/// 判断两个缓存页中是否有当前行的数据
/// </summary>
/// <param name="rowIndex">当前行的index</param>
/// <param name="columnIndex">当前列的index</param>
/// <param name="element">当前Cell的值</param>
/// <returns>如果有 返回true</returns>
private bool IfPageCached_ThenSetElement(int rowIndex,int columnIndex, ref string element)
{
if (IsRowCachedInPage(0, rowIndex))
{
element = cachePages[0].table.Rows[rowIndex % RowsPerPage][columnIndex].ToString();
return true;
}
else if (IsRowCachedInPage(1, rowIndex))
{
element = cachePages[1].table.Rows[rowIndex % RowsPerPage][columnIndex].ToString();
return true;
}
return false;
}
/// <summary>
/// 绘制表格前获取数据的方法
/// </summary>
/// <param name="rowIndex">当前行的index</param>
/// <param name="columnIndex">当前列的index</param>
/// <returns>返回表格的值</returns>
public string RetrieveElement(int rowIndex, int columnIndex)
{
string element = null;
if (IfPageCached_ThenSetElement(rowIndex, columnIndex, ref element))
{
return element;
}
else
{
return RetrieveData_CacheIt_ThenReturnElement(rowIndex, columnIndex);
}
}
/// <summary>
/// 程序初始化时获取第一页和第二页的数据
/// </summary>
private void LoadFirstTwoPages()
{
dataSupply.PageIndex = 1;
DataPage p1 = new DataPage(dataSupply.QuickPageData(), 0);
dataSupply.PageIndex = 2;
DataPage p2 = new DataPage(dataSupply.QuickPageData(), RowsPerPage);
cachePages = new DataPage[]{p1,p2};
this.ColumnCollenction = p1.table.Columns;
}
/// <summary>
/// 获取下一页or上一页未缓存的数据,反回当前Cell的值
/// </summary>
/// <param name="rowIndex">当前行的index</param>
/// <param name="columnIndex">当前列的index</param>
/// <returns>反回当前Cell的值</returns>
private string RetrieveData_CacheIt_ThenReturnElement(int rowIndex, int columnIndex)
{
dataSupply.PageIndex = DataPage.MapCurrentPageIndex(rowIndex);
cachePages[GetIndexToUnusedPage(rowIndex)] = new DataPage(dataSupply.QuickPageData(), rowIndex);
return RetrieveElement(rowIndex, columnIndex);
}
/// <summary>
/// 判断根据当前行获取的数据应该放在哪个页当中缓存起来
/// </summary>
/// <param name="rowIndex">当前行的index</param>
/// <returns>页的index</returns>
private int GetIndexToUnusedPage(int rowIndex)
{
if (rowIndex > cachePages[0].HighestIndex && rowIndex > cachePages[1].HighestIndex)
{
int offsetFromPage0 = rowIndex - cachePages[0].HighestIndex;
int offsetFromPage1 = rowIndex - cachePages[1].HighestIndex;
if (offsetFromPage0 < offsetFromPage1)
{
return 1;
}
return 0;
}
else
{
int offsetFromPage0 = cachePages[0].LowestIndex - rowIndex;
int offsetFromPage1 = cachePages[1].LowestIndex - rowIndex;
if (offsetFromPage0 < offsetFromPage1)
{
return 1;
}
return 0;
}
}
/// <summary>
/// 判断当前行是否在缓存中
/// </summary>
/// <param name="pageNumber">页的index</param>
/// <param name="rowIndex">当前行的index</param>
/// <returns>如果在返回true</returns>
private bool IsRowCachedInPage(int pageNumber, int rowIndex)
{
return rowIndex <= cachePages[pageNumber].HighestIndex && rowIndex >= cachePages[pageNumber].LowestIndex;
}
private static int RowsPerPage;
private DataPage[] cachePages;
public DataColumnCollection ColumnCollenction { get; set; }
private WebPager dataSupply;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="dataSupplier">分页类</param>
/// <param name="rowsPerPage">一页几行</param>
public Cache(WebPager dataSupplier, int rowsPerPage)
{
dataSupply = dataSupplier;
Cache.RowsPerPage = rowsPerPage;
LoadFirstTwoPages();
}
/// <summary>
/// 判断两个缓存页中是否有当前行的数据
/// </summary>
/// <param name="rowIndex">当前行的index</param>
/// <param name="columnIndex">当前列的index</param>
/// <param name="element">当前Cell的值</param>
/// <returns>如果有 返回true</returns>
private bool IfPageCached_ThenSetElement(int rowIndex,int columnIndex, ref string element)
{
if (IsRowCachedInPage(0, rowIndex))
{
element = cachePages[0].table.Rows[rowIndex % RowsPerPage][columnIndex].ToString();
return true;
}
else if (IsRowCachedInPage(1, rowIndex))
{
element = cachePages[1].table.Rows[rowIndex % RowsPerPage][columnIndex].ToString();
return true;
}
return false;
}
/// <summary>
/// 绘制表格前获取数据的方法
/// </summary>
/// <param name="rowIndex">当前行的index</param>
/// <param name="columnIndex">当前列的index</param>
/// <returns>返回表格的值</returns>
public string RetrieveElement(int rowIndex, int columnIndex)
{
string element = null;
if (IfPageCached_ThenSetElement(rowIndex, columnIndex, ref element))
{
return element;
}
else
{
return RetrieveData_CacheIt_ThenReturnElement(rowIndex, columnIndex);
}
}
/// <summary>
/// 程序初始化时获取第一页和第二页的数据
/// </summary>
private void LoadFirstTwoPages()
{
dataSupply.PageIndex = 1;
DataPage p1 = new DataPage(dataSupply.QuickPageData(), 0);
dataSupply.PageIndex = 2;
DataPage p2 = new DataPage(dataSupply.QuickPageData(), RowsPerPage);
cachePages = new DataPage[]{p1,p2};
this.ColumnCollenction = p1.table.Columns;
}
/// <summary>
/// 获取下一页or上一页未缓存的数据,反回当前Cell的值
/// </summary>
/// <param name="rowIndex">当前行的index</param>
/// <param name="columnIndex">当前列的index</param>
/// <returns>反回当前Cell的值</returns>
private string RetrieveData_CacheIt_ThenReturnElement(int rowIndex, int columnIndex)
{
dataSupply.PageIndex = DataPage.MapCurrentPageIndex(rowIndex);
cachePages[GetIndexToUnusedPage(rowIndex)] = new DataPage(dataSupply.QuickPageData(), rowIndex);
return RetrieveElement(rowIndex, columnIndex);
}
/// <summary>
/// 判断根据当前行获取的数据应该放在哪个页当中缓存起来
/// </summary>
/// <param name="rowIndex">当前行的index</param>
/// <returns>页的index</returns>
private int GetIndexToUnusedPage(int rowIndex)
{
if (rowIndex > cachePages[0].HighestIndex && rowIndex > cachePages[1].HighestIndex)
{
int offsetFromPage0 = rowIndex - cachePages[0].HighestIndex;
int offsetFromPage1 = rowIndex - cachePages[1].HighestIndex;
if (offsetFromPage0 < offsetFromPage1)
{
return 1;
}
return 0;
}
else
{
int offsetFromPage0 = cachePages[0].LowestIndex - rowIndex;
int offsetFromPage1 = cachePages[1].LowestIndex - rowIndex;
if (offsetFromPage0 < offsetFromPage1)
{
return 1;
}
return 0;
}
}
/// <summary>
/// 判断当前行是否在缓存中
/// </summary>
/// <param name="pageNumber">页的index</param>
/// <param name="rowIndex">当前行的index</param>
/// <returns>如果在返回true</returns>
private bool IsRowCachedInPage(int pageNumber, int rowIndex)
{
return rowIndex <= cachePages[pageNumber].HighestIndex && rowIndex >= cachePages[pageNumber].LowestIndex;
}
写这个Demo用了三个多小时