首先声明,我是一个小菜鸟,学习WPF也就2个月,如果写的不对的地方,请批评指正。
因为想做一个WPF分页页面,网上找了很多示例程序,大部分都要求使用存储过称,与业务合在一起,控件的通用性不够强。
在我看来,分页控件只需要知道数据有多少页、当前是第几页就可以了,上一页、下一页等命令使用事件或者委托发送出去,实现控件与业务的分离。在这里我采用了MVVM模式来实现分页控件,使用MVVM一定要记住:数据驱动UI界面,尽可能不在后台代码中编写业务逻辑和界面逻辑。示例代码使用了Prism,请引用相关DLL。
首先新建一个自定义控件UserControl
1 <UserControl x:Class="ZhuanKeWebTool.WPF.Content.UCPager" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 mc:Ignorable="d" 7 d:DesignHeight="30" d:DesignWidth="500"> 8 <Grid Background="AliceBlue"> 9 <Grid.ColumnDefinitions> 10 <ColumnDefinition Width="80" /> 11 <ColumnDefinition Width="*" /> 12 <ColumnDefinition Width="20" /> 13 <ColumnDefinition Width="20" /> 14 <ColumnDefinition Width="Auto" /> 15 <ColumnDefinition Width="20" /> 16 <ColumnDefinition Width="20" /> 17 </Grid.ColumnDefinitions> 18 <StackPanel Orientation="Horizontal"> 19 <TextBlock Text="共 " HorizontalAlignment="Left" Height="15" Margin="10,0,0,0"/> 20 <TextBlock Text="{Binding RecordCount}" VerticalAlignment="Center"/> 21 <TextBlock Text=" 条" VerticalAlignment="Center"/> 22 </StackPanel> 23 24 <Button Grid.Column="2" ToolTip="首页" Padding="0" Command="{Binding HomePageCommand}"> 25 <Button.Content> 26 <Image Width="12" Source="../Resources/Images/fastrewind.png"/> 27 </Button.Content> 28 </Button> 29 <Button Grid.Column="3" ToolTip="上一页" Padding="0" Command="{Binding PreviousPageCommand}"> 30 <Button.Content> 31 <Image Width="12" Source="../Resources/Images/skiprewind.png"/> 32 </Button.Content> 33 </Button> 34 35 <WrapPanel Grid.Column="4" HorizontalAlignment="Center" VerticalAlignment="Center"> 36 <TextBlock Text="第" VerticalAlignment="Center"/> 37 <ComboBox ItemsSource="{Binding IndexList}" SelectedItem="{Binding PageIndex}" Width="50"/> 38 <TextBlock Text="页" VerticalAlignment="Center"/> 39 </WrapPanel> 40 41 <Button Grid.Column="5" ToolTip="下一页" Padding="0" Command="{Binding NextPageCommand}"> 42 <Button.Content> 43 <Image Width="12" Source="../Resources/Images/skipforward.png"/> 44 </Button.Content> 45 </Button> 46 <Button Grid.Column="6" ToolTip="尾页" Padding="0" Command="{Binding TailPageCommand}"> 47 <Button.Content> 48 <Image Width="12" Source="../Resources/Images/fastforward.png"/> 49 </Button.Content> 50 </Button> 51 52 </Grid> 53 </UserControl>
控件的样子是这样的:
UserControl的后台代码:
1 public partial class UCPager : UserControl 2 { 3 public UCPagerViewModel UCPagerViewModel { get; private set; } 4 5 public UCPager() 6 { 7 InitializeComponent(); 8 UCPagerViewModel = new UCPagerViewModel(); 9 this.DataContext = UCPagerViewModel; 10 } 11 12 }
后台代码很简单,实例化一个ViewModel,把ViewModel作为属性是想让使用者可以更改ViewModel的属性,达到更改分页控件的目的。
UCPagerViewModel.CS
/// 申明委托 /// </summary> /// <param name="e"></param> /// <returns></returns> public delegate void EventPagingHandler(EventPagingArg e); /// <summary> /// 自定义事件参数 /// </summary> public class EventPagingArg : EventArgs { public int PageIndex { get; set; } public EventPagingArg(int pageIndex) { PageIndex = pageIndex; } } public class UCPagerViewModel : NotificationObject { #region 构造器 public UCPagerViewModel() { NextPageCommand = new DelegateCommand(new Action(NextPageCommandExecute)); PreviousPageCommand = new DelegateCommand(new Action(PreviousPageCommandExecute)); HomePageCommand = new DelegateCommand(new Action(HomePageCommandExecute)); TailPageCommand = new DelegateCommand(new Action(TailPageCommandExecute)); } #endregion #region Property private int pageIndex; public int PageIndex { get { return pageIndex; } set { pageIndex = value; this.RaisePropertyChanged("PageIndex"); if (PagingHandler != null) PagingHandler.Invoke(new EventPagingArg(PageIndex)); } } private int pageSize; public int PageSize { get { return pageSize; } set { pageSize = value; this.RaisePropertyChanged("PageSize"); } } private int pageCount; public int PageCount { get { return pageCount; } set { pageCount = value; this.RaisePropertyChanged("PageCount"); } } private int recordCount; public int RecordCount { get { return recordCount; } set { recordCount = value; this.RaisePropertyChanged("RecordCount"); } } private List<int> indexList; public List<int> IndexList { get { return indexList; } set { indexList = value; this.RaisePropertyChanged("IndexList"); } } #endregion #region 命令 public DelegateCommand NextPageCommand { get; set; } public DelegateCommand PreviousPageCommand { get; set; } public DelegateCommand HomePageCommand { get; set; } public DelegateCommand TailPageCommand { get; set; } private void NextPageCommandExecute() { if(PageIndex<PageCount) PageIndex = PageIndex + 1; } private void PreviousPageCommandExecute() { if (PageIndex >1) PageIndex = PageIndex - 1; } private void HomePageCommandExecute() { PageIndex = 1; } private void TailPageCommandExecute() { PageIndex = PageCount; } #endregion #region 事件 public EventPagingHandler PagingHandler { get; set; } #endregion }
UCPagerViewModel.CS包含三个部分,定义了一个委托、一个事件参数和ViewModel。使用该控件时先向其传入PageIndex、PageCount、RecordCount、PageSize和IndexList参数控制控件的现实,同时注册一个委托,当按下按钮或者选择页码时,分页控件会调用注册的委托,同时传递选择的页码。
分页控件使用示例:
<StackPanel> <DataGrid x:Name="emailDataGrid" ItemsSource="{Binding EmailList}" AutoGenerateColumns="False" VerticalGridLinesBrush="Red" BorderBrush="DarkBlue" BorderThickness="1" LoadingRow="emailDataGrid_LoadingRow" CanUserAddRows="False" IsReadOnly="True"> <DataGrid.Columns> <DataGridTextColumn Header="用户名" Width="100" Binding="{Binding UserName}"/> <DataGridTextColumn Header="密码" Width="*" Binding="{Binding Password}"/> </DataGrid.Columns> </DataGrid> <local:UCPager x:Name="mailPager"/> </StackPanel>
后台代码:
public partial class NetsMail : UserControl { public NetsMail() { InitializeComponent(); UCPagerViewModel pagerViewModel = this.mailPager.UCPagerViewModel; NetsMailViewModel model = new NetsMailViewModel(pagerViewModel); this.DataContext = model; } private void emailDataGrid_LoadingRow(object sender, DataGridRowEventArgs e) { e.Row.Header = e.Row.GetIndex() + 1; } }
在后台代码中,首先获取分页控件的ViewModel,然后将分页控件的ViewModel传入自己的ViewModel
public NetsMailViewModel(UCPagerViewModel model) { pagerViewModel = model; pagerViewModel.PagingHandler += new EventPagingHandler(e=>PageIndex=e.PageIndex); NetsService = App.Container.GetExportedValue<INetsDesktopContract>(); int recordCount; PageIndex = 1; emailList = NetsService.GetEmailAccounts(PageIndex, 20, out recordCount); pagerViewModel.PageIndex = PageIndex; pagerViewModel.PageSize = 20; pagerViewModel.RecordCount = recordCount; pagerViewModel.PageCount = recordCount % 20 > 0 ? recordCount / 20 + 1 : recordCount / 20; List<int> indexList = new List<int>(); for (int i = 0; i < pagerViewModel.PageCount; i++) { indexList.Add(i + 1); } pagerViewModel.IndexList = indexList; }
在ViewModel中获取用于显示的数据,同时向分页控件传入显示需要的数据。注意
pagerViewModel.PagingHandler += new EventPagingHandler(e=>PageIndex=e.PageIndex);
这句话,主要作用是注册一个委托,用于获取分页控件传递过来的PageIndex。