65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows Presentation Foundation (WPF) 的小型分页控件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (13投票s)

2012年6月27日

CPOL

5分钟阅读

viewsIcon

63537

downloadIcon

4358

用于控制 Windows Presentation Foundation 分页的一个小型控件。

Sample Image - maximum width is 600 pixels

引言

分页解决方案在 Web 应用程序中是一个常见问题,但在 Windows 应用程序中却不那么常见。在我的实际工作中需要分页,我发现 WPF 中没有控件可以控制分页操作。于是我决定创建一个简单的控件来分页 DataGrid 或其他 WPF 中的数据控件。该控件不绑定到 Grid 控件,但可以与其他数据控件一起使用。您可以在文章的第一张图中看到该控件的工作效果。

背景

在我的解决方案中,我需要分页用户结果,以停止对用户没有实际用途的大量数据处理。我没有找到一个现成的 WPF 控件(也许我没有做太多研究),但我找到了一篇非常有用的文章,它被用作设计此控件的基础。相关文章可以在 [1] 中找到,作者是 Ben Foster。这篇文章本身并没有开发控件,但为我开发分页控件提供了基础。事实上,文章描述了一个分页类的基本接口,以及访问不同数据源的方法。

分页控件的工作原理是,当用户想要更改数据页时,它应该通知应用程序。此外,分页控件还应执行以下任务:

  • 跟踪要显示的记录总数,
  • 要显示在数据绑定控件中的每个页面(页面大小)的数量(行数)。
  • 跟踪页面索引的位置。
  • 控制控件按钮的可见性,以帮助用户避免发送无意义的索引更改。

功能描述可以在图 2 中看到。

Sample Image - maximum width is 600 pixels

此外,该控件还应支持在 AXML 代码中配置控件。为此,三个必要的属性被声明为依赖属性,并且可以在 XAML 代码中配置。另外,ChangeindexEvent 被重路由为一个命令,以便由窗口或 MVVC 架构执行。

下图展示了用户可以通过控件执行的操作以及程序可以用来操作控件的属性和视觉交互。

Sample Image - maximum width is 600 pixels

索引按钮和更改页面大小都会生成一个 ChangeIndex 事件,以通知容器页面索引已更改。对于 PageSize,索引会自动设置为 1,以避免由于页面大小更改而可能出现的错误值。

下一节将介绍如何在简单应用程序中使用此控件。

使用代码

要使用示例和代码,您需要以下内容:

  • 在您的计算机上安装 SQL Server 或 SQL Express(2005 或 2008)。
  • Northwind 数据库(您可以在 http://sqlserversamples.codeplex.com/ 找到适合您的版本)。
  • 在运行示例或代码之前,请打开配置文件或代码中的属性,并根据您的计算机配置进行必要的更改。

我们在这里分步通过一个示例,介绍如何在 Windows 的代码隐藏中使用此控件。

正如您在源代码中看到的,控件的所有文件都在 GridPaging 文件夹中。

Folder of Paging Control

您可以将该文件夹复制到您的项目中,也可以根据需要编译独立的 DLL。当您构建项目时,可以在工具箱中看到 GridPaging 控件。将其拖放到您的窗口表面上您想要使用它的位置。

Folder of Paging Control

随心所欲地个性化您的控件,您可以在源选项卡中看到如下内容:

XAML Code to use the control

要使用该控件,您应该实现自定义命令以用于与该控件的通信。要实现一个命令,如您在示例中看到的,您需要执行以下操作:

/// Initializes a new instance of the class. 
public MainWindow() 
{ 
   InitializeComponent(); 
   this.listorders = new List<Orders>();
    
   // Binding with the ChangedIndexCommand on GridPaging.........................................
   // Create de Command.
   this.changedIndex = new RoutedUICommand("ChangedIndex", "ChangedIndex", typeof(MainWindow));
    
   // Assign the command to GridPaging Command. 
   gridPaging1.ChangedIndexCommand = this.changedIndex; 

   // Binding Command 
   CommandBinding abinding = new CommandBinding  { Command = this.changedIndex }; 

   // Binding Handler to executed. 
   abinding.Executed += this.OnChangeIndexCommandHandler; 
   this.CommandBindings.Add(abinding); 
   
   // ...........................................................................................
}

上面的代码声明了一个用于 GridPaging 控件的命令,并将其分配给该控件。然后,您需要创建您的命令处理程序(在代码中称为 OnChangeIndexCommandHandler),您可以在以下代码片段中看到其实现。

private void OnChangeIndexCommandHandler(object sender, ExecutedRoutedEventArgs e) 
{
    var pageIndex = gridPaging1.PageIndex; 
    var pageSize = gridPaging1.PageSize; 
    gridPaging1.TotalCount = this.ExecuteQueryReturnTotalItem(pageIndex, pageSize); 
}

实现方式始终相同,只有获取数据的方法性质不同。在代码示例中,有一个用于分页 MS SQL Server 表的方法。但您也可以查询 Oracle 或其他数据库,以及实体、列表或 nHibernate 代码。

您可以看到,您使用了 GridPaging 的三个属性:Page Index 和 PageSize。这些用作输出参数,用于告知查询获取数据所需的必要位置。

非常重要的一点是,您的查询还应该返回不分页的全部数据计数。这对于保持正确的总页数非常重要。也就是说,您必须首先查询实际查询的总行数,然后仅返回页面中的行。MS SQL Server 的此类查询示例在以下示例中:

/// <summary>
/// Refactoring for Get the query. 
/// </summary>
/// <param  name="pageIndex" />
/// The page index. 
/// <param name="pageSize" />
/// The page size.
/// <returns>
/// The row count. 
/// </returns>
private int ExecuteQueryReturnTotalItem(int pageIndex, int pageSize) 
{ 
	// Calculating the initial and final row. 
	var initialRow = (pageIndex - 1) * pageSize; 
	var finalRow = initialRow + pageSize; 

	// NOTE Change your connection string in app config file to get your proper connection string. 
	string connString = Properties.Settings.Default.NordConnection; 
	var conn = new SqlConnection(connString); 
	const string SqlQueryCount = "select count(OrderId) from dbo.Orders"; 
	try
	{ 
		SqlCommand commcount = new SqlCommand(SqlQueryCount, conn); 
		conn.Open(); 
		var rowCount = Convert.ToInt32(commcount.ExecuteScalar()); 
		const string SqlQuery = @"use Northwind; 
		   WITH Members AS ( select ROW_NUMBER() 
		   OVER (ORDER BY OrderID DESC) as row, 
		   OrderDate, OrderId, ShipName, ShipPostalCode from dbo.Orders )
		   Select row, OrderDate, OrderId, ShipName, ShipPostalCode 
		   FROM Members 
		   WHERE row BETWEEN @InitialRow AND @EndRow
		   ORDER BY row ASC;";
 
		SqlCommand command = new SqlCommand(SqlQuery, conn); 
 		command.Parameters.AddWithValue("@InitialRow", initialRow); 
 		command.Parameters.AddWithValue("@EndRow", finalRow); 
 		var reader = command.ExecuteReader(); 
 		this.listorders = new List <Orders>();
  		while (reader.Read())
   		{ 
   			var o = new Orders 
    		{ 
	   	        OrderDate = Convert.ToDateTime(reader["OrderDate"]), 
   			    OrderId = Convert.ToInt32(reader["OrderId"]), 
   			    ShipName = reader["ShipName"].ToString(),
    			    ShipPostalCode = reader["ShipPostalCode"].ToString() 
    		    }; 
    			this.listorders.Add(o); 
    		}
    			this.dgOrdersGrid.ItemsSource = this.listorders; return rowCount; 
 	    }
 	    catch (Exception ex) 
 	    { 
 	        MessageBox.Show(ex.Message);
 	        return 0; 
 	    } 
 	    finally
 	    { 
 	        if (conn.State != ConnectionState.Closed) { conn.Close(); }
 	    }

控件初始化时页面大小为 500,您可以将其分配给 PageSize 属性来修改,值为 50、100、500 或 1000。如果您想要其他值,可以修改控件代码。您可以在页面大小组合框项目中输入其他值。

在 MVVC 开发中使用 GridPaging

GridPagingPageSizePageIndexTotalCount 属性公开为依赖属性,还将 ChangedIndexCommand 命令公开。然后,您可以在控件的 XAML 代码中使用它们,以便与 ViewModel 中的属性进行链接。您也可以直接在 AXML 中分配命令。

关注点

如您所见,使用此控件并不复杂。您可以使用它来防止用户返回大量行数据。这可以避免 UI 变得无响应,或者使网格控件中的自动筛选变慢。

参考文献

[1] 使用 ASP.NET MVC 和 Nhibernate 的简单分页。作者:Ben Foster。2010 年 5 月

历史

  • 2012 年 6 月 30 日 - 初始发布。
© . All rights reserved.