WPF 中的 DataView 分页





4.00/5 (10投票s)
WPF 中 DataView 的自定义分页。
引言
在 WPF (Windows Presentation Foundation) 中,与 Visual Studio 2005 不同的是,GridView
控件没有内置的分页支持 (我认为。可能我遗漏了什么)。 当我使用 GridView
在 WPF 中进行一些测试编码并想要分页支持时,我像往常一样在 Google 上搜索,但没有用。 经过大量搜索后,我决定为此目的实现自定义分页。 完成后,我决定与他人分享,因为关于 WPF 的文章并不多。

在本文中,我将解释如何创建 DataView
,如何将其绑定到动态数据源,并且我还将解释关于实现分页。 分页逻辑非常简单,可以在任何其他类似情况下使用。
在这里,我将使用 Northwind 作为数据库和两个表 Products
作为数据。
首先,创建一个 GridView
来显示数据。 要创建 gridview
,请使用此语法
<ListView Name="lstProducts">
<ListView.View>
<GridView></GridView>
</ListView.View>
</ListView>
要创建列,请使用此语法
<GridViewColumn Header="ProductID"></GridViewColumn>
要将数据源绑定到 gridview
,请将 ItemsSource
属性设置为 "{Binding}"
,并将数据库字段绑定到 gridviewcolumn
,将 DisplayMemberBinding
属性设置为 "{Binding Path=[FieldName]}"
。
因此,这是可绑定 gridview
的 XAML
<ListView Margin="15,115,15,48" Name="lstProducts" ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="ProductID"
DisplayMemberBinding="{Binding Path=ProductID}"></GridViewColumn>
<GridViewColumn Header="Product Name"
DisplayMemberBinding="{Binding Path=ProductName}"></GridViewColumn>
<GridViewColumn Header="SupplierID"
DisplayMemberBinding="{Binding Path=SupplierID}"></GridViewColumn>
<GridViewColumn Header="CategoryID"
DisplayMemberBinding="{Binding Path=CategoryID}"></GridViewColumn>
<GridViewColumn Header="Qty. Per Unit"
DisplayMemberBinding="{Binding Path=QuantityPerUnit}"></GridViewColumn>
<GridViewColumn Header="Unit Price"
DisplayMemberBinding="{Binding Path=UnitPrice}"></GridViewColumn>
<GridViewColumn Header="In Stock"
DisplayMemberBinding="{Binding Path=UnitInStock}"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
在代码隐藏中,编写代码将数据绑定到 gridview
。 这是绑定数据的函数
private void ListProducts()
{
sqlCon = new SqlConnection();
sqlCon.ConnectionString = \\ConnectionString.
cmd = new SqlCommand();
cmd.Connection = sqlCon;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM Products";
sqlDa = new SqlDataAdapter();
sqlDa.SelectCommand = cmd;
ds = new DataSet();
try
{
sqlDa.Fill(ds,"Products");
if (ds.Tables["Products"].Rows.Count > 0)
{
lstProducts.DataContext = ds.Tables["Products"].DefaultView;
}
else
{
MessageBox.Show("Message");
}
}
catch (Exception ex)
{
MessageBox.Show("Error Message");
}
finally
{
sqlDa.Dispose();
cmd.Dispose();
sqlCon.Dispose();
}
}
要在窗口的 Loaded
事件(Visual Studio 2005 中的 Load
事件)中调用此函数,请像这样更新 XAML
<Window
.......
Loaded="OnLoad"
>
在 *.cs 文件中编写 OnLoad
处理程序的代码。
private void OnLoad(object sender, System.EventArgs e)
{
ListProducts();
}
现在我们有了列出所有产品的网格。 让我们开始实现 分页
。 首先,我们需要为 分页
创建 button
。 Button
使用 <Button></Button>
标签创建。 对于单击事件,请使用 Click="EventName"
。
因此,这是带有事件的 button
的 XAML
<Button Height="23" HorizontalAlignment="Left" Margin="18,0,0,22"
Name="btnFirst" VerticalAlignment="Bottom" Width="40"
Content="<<" Click="btnFirst_Click" Opacity="0.75">
</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,474,22"
Name="btnNext" VerticalAlignment="Bottom" Width="40"
Content=">" Click="btnNext_Click" Opacity="0.75">
</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,429,22"
VerticalAlignment="Bottom" Width="40" Name="btnLast"
Click="btnLast_Click" Opacity="0.75" Content=">>">
</Button>
<Button Height="23" Margin="62,0,551,22" VerticalAlignment="Bottom"
Name="btnPrev" Click="btnPrev_Click" Opacity="0.75" Content="<">
</Button>
在代码隐藏中,编写代码进行 分页
。 对于 分页
,我创建了四个 private
成员
//For holding the data globally.
DataTable dt_Products = new DataTable("Products");
//For storing the current page number.
private int paging_PageIndex = 1;
//For storing the Paging Size. Here it is static but you can use a property
//to expose and update value.
private int paging_NoOfRecPerPage = 20;
//To check the paging direction according to use selection.
private enum PagingMode {First = 1,Next = 2,Previous = 3,Last = 4};
我们使用 dt_Products
来存储从数据库检索的数据。 为此,稍微更新一下 ListProducts()
函数。 检索数据后,我们必须根据 paging_NoOfRecPerPage
的值 (这里是 20) 显示第一组记录。 为此,我使用 clone
方法创建了一个与 dt_Products
具有相同架构的临时表。
private void ListProducts()
{
...........
paging_PageIndex = 1;\\For default
sqlDa.Fill(dt_Products);
if (dt_Products.Rows.Count > 0)
{
DataTable tmpTable = new DataTable();
//Copying the schema to the temporary table.
tmpTable = dt_Products.Clone();
//If total record count is greater than page size then import records
//from 0 to pagesize (here 20)
//Else import reports from 0 to total record count.
if (dt_Products.Rows.Count >= paging_NoOfRecPerPage)
{
for (int i = 0; i < paging_NoOfRecPerPage; i++)
{
tmpTable.ImportRow(dt_Products.Rows[i]);
}
}
else
{
for (int i = 0; i < dt_Products.Rows.Count; i++)
{
tmpTable.ImportRow(dt_Products.Rows[i]);
}
}
//Bind the table to the gridview.
lstProducts.DataContext = tmpTable.DefaultView;
//Dispose the temporary table.
tmpTable.Dispose();
}
现在,仅显示前 20 条(页面大小)记录。 现在我们必须编写导航代码。 让我们为此创建一个函数
private void CustomPaging(int mode)
{
//There is no need for these variables but i created them just for readability
int totalRecords = dt_Products.Rows.Count;
int pageSize = paging_NoOfRecPerPage;
//If total record count is less than the page size then return.
if (totalRecords <= pageSize)
{
return;
}
switch (mode)
{
case (int)PagingMode.Next:
if (totalRecords > (paging_PageIndex * pageSize))
{
DataTable tmpTable = new DataTable();
tmpTable = dt_Products.Clone();
if (totalRecords >= ((paging_PageIndex * pageSize) + pageSize))
{
for (int i = paging_PageIndex * pageSize; i <
((paging_PageIndex * pageSize) + pageSize); i++)
{
tmpTable.ImportRow(dt_Products.Rows[i]);
}
}
else
{
for (int i = paging_PageIndex * pageSize; i < totalRecords; i++)
{
tmpTable.ImportRow(dt_Products.Rows[i]);
}
}
paging_PageIndex += 1;
lstProducts.DataContext = tmpTable.DefaultView;
tmpTable.Dispose();
}
break;
case (int)PagingMode.Previous:
if (paging_PageIndex > 1)
{
DataTable tmpTable = new DataTable();
tmpTable = dt_Products.Clone();
paging_PageIndex -= 1;
for (int i = ((paging_PageIndex * pageSize) - pageSize);
i < (paging_PageIndex * pageSize); i++)
{
tmpTable.ImportRow(dt_Products.Rows[i]);
}
lstProducts.DataContext = tmpTable.DefaultView;
tmpTable.Dispose();
}
break;
case (int)PagingMode.First:
paging_PageIndex = 2;
CustomPaging((int)PagingMode.Previous);
break;
case (int)PagingMode.Last:
paging_PageIndex = (totalRecords/pageSize);
CustomPaging((int)PagingMode.Next);
break;
}
}
分页
功能已完成。 我们只需要在按钮单击时调用并传递正确的模式。
private void btnFirst_Click(object sender, System.EventArgs e)
{
CustomPaging((int)PagingMode.First);
}
private void btnNext_Click(object sender, System.EventArgs e)
{
CustomPaging((int)PagingMode.Next);
}
private void btnPrev_Click(object sender, System.EventArgs e)
{
CustomPaging((int)PagingMode.Previous);
}
private void btnLast_Click(object sender, System.EventArgs e)
{
CustomPaging((int)PagingMode.Last);
}
这就是 分页
的全部内容。
如果您想同时显示 分页
信息和页码,请创建两个 label
<Label Height="23.277" HorizontalAlignment="Left" Margin="14.37,89.723,0,0"
Name="lblPagingInfo" VerticalAlignment="Top" Width="282.63"/>
<Label Height="23.277" HorizontalAlignment="Left" Margin="108.37,0,0,23"
Name="lblPageNumber" VerticalAlignment="Bottom" Width="26.63" Content="1"/>
为了显示 分页
信息,让我们编写一个简单的函数。 将此函数调用添加到 CustomPaging()
函数中的 switch
块之外。 完成。 编译并运行。
这是完整的代码
XAML
<Window
.......
Loaded="OnLoad"
>
<Grid>
<ListView Margin="15,115,15,48" Name="lstProducts" ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="ProductID"
DisplayMemberBinding="{Binding Path=ProductID}"></GridViewColumn>
<GridViewColumn Header="Product Name"
DisplayMemberBinding="{Binding Path=ProductName}"></GridViewColumn>
<GridViewColumn Header="SupplierID"
DisplayMemberBinding="{Binding Path=SupplierID}"></GridViewColumn>
<GridViewColumn Header="CategoryID"
DisplayMemberBinding="{Binding Path=CategoryID}"></GridViewColumn>
<GridViewColumn Header="Qty. Per Unit"
DisplayMemberBinding="{Binding Path=QuantityPerUnit}"></GridViewColumn>
<GridViewColumn Header="Unit Price"
DisplayMemberBinding="{Binding Path=UnitPrice}"></GridViewColumn>
<GridViewColumn Header="In Stock"
DisplayMemberBinding="{Binding Path=UnitInStock}"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<Button Height="23" HorizontalAlignment="Left" Margin="18,0,0,22"
Name="btnFirst" VerticalAlignment="Bottom" Width="40" Content="<<"
Click="btnFirst_Click" Opacity="0.75">
</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,474,22"
Name="btnNext" VerticalAlignment="Bottom" Width="40" Content=">"
Click="btnNext_Click" Opacity="0.75">
</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,429,22"
VerticalAlignment="Bottom" Width="40" Name="btnLast"
Click="btnLast_Click" Opacity="0.75" Content=">>">
</Button>
<Button Height="23" Margin="62,0,551,22" VerticalAlignment="Bottom"
Name="btnPrev" Click="btnPrev_Click" Opacity="0.75" Content="<">
</Button>
<Label Height="23.277" HorizontalAlignment="Left" Margin="14.37,89.723,0,0"
Name="lblPagingInfo" VerticalAlignment="Top" Width="282.63"/>
<Label Height="23.277" HorizontalAlignment="Left" Margin="108.37,0,0,23"
Name="lblPageNumber" VerticalAlignment="Bottom" Width="26.63" Content="1"/>
</Grid>
</Window>
C#
//For holding the data globally.
DataTable dt_Products = new DataTable("Products");
//For storing the current page number.
private int paging_PageIndex = 1;
//For storing the Paging Size. Here it is static but you can use a property
//to expose and update value.
private int paging_NoOfRecPerPage = 20;
//To check the paging direction according to use selection.
private enum PagingMode {First = 1,Next = 2,Previous = 3,Last = 4};
private void OnLoad(object sender, System.EventArgs e)
{
ListProducts();
}
private void btnFirst_Click(object sender, System.EventArgs e)
{
CustomPaging((int)PagingMode.First);
}
private void btnNext_Click(object sender, System.EventArgs e)
{
CustomPaging((int)PagingMode.Next);
}
private void btnPrev_Click(object sender, System.EventArgs e)
{
CustomPaging((int)PagingMode.Previous);
}
private void btnLast_Click(object sender, System.EventArgs e)
{
CustomPaging((int)PagingMode.Last);
}
private void ListProducts()
{
sqlCon = new SqlConnection();
sqlCon.ConnectionString = \\ConnectionString.
cmd = new SqlCommand();
cmd.Connection = sqlCon;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM Products";
sqlDa = new SqlDataAdapter();
sqlDa.SelectCommand = cmd;
try
{
paging_PageIndex = 1;\\For default
sqlDa.Fill(dt_Products);
if (dt_Products.Rows.Count > 0)
{
DataTable tmpTable = new DataTable();
//Copying the schema to the temporary table.
tmpTable = dt_Products.Clone();
//If total record count is greater than page size then
//import records from 0 to pagesize (here 20)
//Else import reports from 0 to total record count.
if (dt_Products.Rows.Count >= paging_NoOfRecPerPage)
{
for (int i = 0; i < paging_NoOfRecPerPage; i++)
{
tmpTable.ImportRow(dt_Products.Rows[i]);
}
}
else
{
for (int i = 0; i < dt_Products.Rows.Count; i++)
{
tmpTable.ImportRow(dt_Products.Rows[i]);
}
}
//Bind the table to the gridview.
lstProducts.DataContext = tmpTable.DefaultView;
//Dispose the temporary table.
tmpTable.Dispose();
}
else
{
MessageBox.Show("Message");
}
}
catch (Exception ex)
{
MessageBox.Show("Error Message");
}
finally
{
sqlDa.Dispose();
cmd.Dispose();
sqlCon.Dispose();
}
}
private void CustomPaging(int mode)
{
//There is no need for these variables but i created them just for readability
int totalRecords = dt_Products.Rows.Count;
int pageSize = paging_NoOfRecPerPage;
//If total record count is less than the page size then return.
if (totalRecords <= pageSize)
{
return;
}
switch (mode)
{
case (int)PagingMode.Next:
if (totalRecords > (paging_PageIndex * pageSize))
{
DataTable tmpTable = new DataTable();
tmpTable = dt_Products.Clone();
if (totalRecords >= ((paging_PageIndex * pageSize) + pageSize))
{
for (int i = paging_PageIndex * pageSize;
i < ((paging_PageIndex * pageSize) + pageSize); i++)
{
tmpTable.ImportRow(dt_Products.Rows[i]);
}
}
else
{
for (int i = paging_PageIndex * pageSize; i < totalRecords; i++)
{
tmpTable.ImportRow(dt_Products.Rows[i]);
}
}
paging_PageIndex += 1;
lstProducts.DataContext = tmpTable.DefaultView;
tmpTable.Dispose();
}
break;
case (int)PagingMode.Previous:
if (paging_PageIndex > 1)
{
DataTable tmpTable = new DataTable();
tmpTable = dt_Products.Clone();
paging_PageIndex -= 1;
for (int i = ((paging_PageIndex * pageSize) - pageSize);
i < (paging_PageIndex * pageSize); i++)
{
tmpTable.ImportRow(dt_Products.Rows[i]);
}
lstProducts.DataContext = tmpTable.DefaultView;
tmpTable.Dispose();
}
break;
case (int)PagingMode.First:
paging_PageIndex = 2;
CustomPaging((int)PagingMode.Previous);
break;
case (int)PagingMode.Last:
paging_PageIndex = (totalRecords/pageSize);
CustomPaging((int)PagingMode.Next);
break;
}
DisplayPagingInfo();
}
private void DisplayPagingInfo()
{
//There is no need for these variables but i created them just for readability
int totalRecords = dt_Products.Rows.Count;
int pageSize = paging_NoOfRecPerPage;
string pagingInfo = "Displaying " + (((paging_PageIndex-1)*pageSize)+1) +
to " + paging_PageIndex*pageSize ;
if (dt_Products.Rows.Count < (paging_PageIndex * pageSize))
{
pagingInfo = "Displaying " + (((paging_PageIndex - 1) * pageSize) + 1) +
to " + totalRecords;
}
lblPagingInfo.Content = pagingInfo;
lblPageNumber.Content = paging_PageIndex;
}