在WPF中,通常會選用DataGrid/ListView進行數據展示,如果數據量不多,可以直接一個頁面顯示出來。如果數據量很大,2000條數據,一次性顯示在一個頁面中,不僅消耗資源,而且用戶體驗也很糟糕。這篇博客將介紹如何創建一個分頁控件。
為了簡單起見,這個分頁控件目前只有 首頁/上一頁/下一頁/末頁/總頁數/第幾頁 等功能。實現思路,首頁/上一頁/下一頁/末頁 這四個通過路由事件來實現,在使用時可以使用命令進行綁定,或者直接使用均可。總頁數和第幾頁通過依賴屬性來實現,使用時將頁數進行綁定顯示即可。示例代碼如下:
Pager控件:
<UserControl.Resources><Style TargetType="{x:Type Button}"><Setter Property="Width" Value="22"/><Setter Property="Height" Value="22"/></Style></UserControl.Resources><Grid><StackPanel Orientation="Horizontal"><Button x:Name="FirstPageButton" Margin="5,0" Click="FirstPageButton_Click"><Path Width="7" Height="10" Data="M0,0L0,10 M0,5L6,2 6,8 0,5" Stroke="Black" StrokeThickness="1" Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center" /></Button><Button x:Name="PreviousPageButton" Margin="0,0,5,0" Click="PreviousPageButton_Click"><Path Width="8" Height="8" Data="M0,4L8,0 8,8z" Stroke="Black" Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center" /></Button><TextBlock VerticalAlignment="Center"><Run Text="第"/><Run x:Name="rCurrent" Text="0"/><Run Text="頁"/></TextBlock><Button Margin="5,0" x:Name="NextPageButton" Click="NextPageButton_Click"><Path Width="8" Height="8" Data="M0,4L8,0 8,8z" Stroke="Black" Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center"><Path.RenderTransform><RotateTransform Angle="180" CenterX="4" CenterY="4" /></Path.RenderTransform></Path></Button><Button Margin="0,0,5,0" x:Name="LastPageButton" Click="LastPageButton_Click"><Path x:Name="MainPath" Width="7" Height="10" Data="M0,0L0,10 M0,5 L6,2 6,8 0,5" Stroke="Black" StrokeThickness="1" Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center"><Path.RenderTransform><RotateTransform Angle="180" CenterX="3" CenterY="5" /></Path.RenderTransform></Path></Button><TextBlock VerticalAlignment="Center"><Run Text="共"/><Run x:Name="rTotal" Text="0"/><Run Text="頁"/></TextBlock></StackPanel> </Grid>
C#:


public partial class Pager : UserControl{public static RoutedEvent FirstPageEvent;public static RoutedEvent PreviousPageEvent;public static RoutedEvent NextPageEvent;public static RoutedEvent LastPageEvent;public static readonly DependencyProperty CurrentPageProperty;public static readonly DependencyProperty TotalPageProperty;public string CurrentPage{get { return (string)GetValue(CurrentPageProperty); }set { SetValue(CurrentPageProperty, value); }}public string TotalPage{get { return (string)GetValue(TotalPageProperty); }set { SetValue(TotalPageProperty, value); }}public Pager(){InitializeComponent();}static Pager(){FirstPageEvent = EventManager.RegisterRoutedEvent("FirstPage", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(Pager));PreviousPageEvent = EventManager.RegisterRoutedEvent("PreviousPage", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(Pager));NextPageEvent = EventManager.RegisterRoutedEvent("NextPage", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(Pager));LastPageEvent = EventManager.RegisterRoutedEvent("LastPage", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(Pager));CurrentPageProperty = DependencyProperty.Register("CurrentPage", typeof(string), typeof(Pager), new PropertyMetadata(string.Empty,new PropertyChangedCallback(OnCurrentPageChanged)));TotalPageProperty = DependencyProperty.Register("TotalPage", typeof(string), typeof(Pager), new PropertyMetadata(string.Empty,new PropertyChangedCallback(OnTotalPageChanged)));}public event RoutedEventHandler FirstPage{add { AddHandler(FirstPageEvent, value); }remove { RemoveHandler(FirstPageEvent, value); }}public event RoutedEventHandler PreviousPage{add { AddHandler(PreviousPageEvent, value); }remove { RemoveHandler(PreviousPageEvent, value); }}public event RoutedEventHandler NextPage{add { AddHandler(NextPageEvent, value); }remove { RemoveHandler(NextPageEvent, value); }}public event RoutedEventHandler LastPage{add { AddHandler(LastPageEvent, value); }remove { RemoveHandler(LastPageEvent, value); }}public static void OnTotalPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){Pager p = d as Pager;if(p != null){Run rTotal = (Run)p.FindName("rTotal");rTotal.Text = (string)e.NewValue;}}private static void OnCurrentPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){Pager p = d as Pager;if(p != null){Run rCurrrent = (Run)p.FindName("rCurrent");rCurrrent.Text = (string)e.NewValue;}}private void FirstPageButton_Click(object sender, RoutedEventArgs e){RaiseEvent(new RoutedEventArgs(FirstPageEvent, this));}private void PreviousPageButton_Click(object sender, RoutedEventArgs e){RaiseEvent(new RoutedEventArgs(PreviousPageEvent, this));}private void NextPageButton_Click(object sender, RoutedEventArgs e){RaiseEvent(new RoutedEventArgs(NextPageEvent, this));}private void LastPageButton_Click(object sender, RoutedEventArgs e){RaiseEvent(new RoutedEventArgs(LastPageEvent, this));}}
在MainWindow中,
XAML:
<Grid><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><DataGrid Grid.Row="0" ItemsSource="{Binding FakeSource}" AutoGenerateColumns="False" CanUserAddRows="False"><DataGrid.Columns><DataGridTextColumn Header="Item Id" Binding="{Binding Id}" Width="80"/><DataGridTextColumn Header="Item Name" Binding="{Binding ItemName}" Width="180"/></DataGrid.Columns></DataGrid><local:Pager TotalPage="{Binding TotalPage}"CurrentPage="{Binding CurrentPage, Mode=TwoWay}" HorizontalAlignment="Center"Grid.Row="1"><i:Interaction.Triggers><i:EventTrigger EventName="FirstPage"><i:InvokeCommandAction Command="{Binding FirstPageCommand}" /></i:EventTrigger><i:EventTrigger EventName="PreviousPage"><i:InvokeCommandAction Command="{Binding PreviousPageCommand}"/></i:EventTrigger><i:EventTrigger EventName="NextPage"><i:InvokeCommandAction Command="{Binding NextPageCommand}" /></i:EventTrigger><i:EventTrigger EventName="LastPage"><i:InvokeCommandAction Command="{Binding LastPageCommand}"/></i:EventTrigger></i:Interaction.Triggers></local:Pager></Grid>
MainViewModel類:


public class MainViewModel : ViewModel{private ICommand _firstPageCommand;public ICommand FirstPageCommand{get{return _firstPageCommand;}set{_firstPageCommand = value;}}private ICommand _previousPageCommand;public ICommand PreviousPageCommand{get{return _previousPageCommand;}set{_previousPageCommand = value;}}private ICommand _nextPageCommand;public ICommand NextPageCommand{get{return _nextPageCommand;}set{_nextPageCommand = value;}}private ICommand _lastPageCommand;public ICommand LastPageCommand{get{return _lastPageCommand;}set{_lastPageCommand = value;}}private int _pageSize;public int PageSize{get{return _pageSize;}set{if(_pageSize != value){_pageSize = value;OnPropertyChanged("PageSize");}}}private int _currentPage;public int CurrentPage{get{return _currentPage;}set{if(_currentPage != value){_currentPage = value;OnPropertyChanged("CurrentPage");}}}private int _totalPage;public int TotalPage{get{return _totalPage;}set{if(_totalPage != value){_totalPage = value;OnPropertyChanged("TotalPage");}}}private ObservableCollection<FakeDatabase> _fakeSoruce;public ObservableCollection<FakeDatabase> FakeSource{get{return _fakeSoruce;}set{if(_fakeSoruce != value){_fakeSoruce = value;OnPropertyChanged("FakeSource");}}}private List<FakeDatabase> _source;public MainViewModel(){_currentPage = 1;_pageSize = 20;FakeDatabase fake = new FakeDatabase();_source = fake.GenerateFakeSource();_totalPage = _source.Count / _pageSize;_fakeSoruce = new ObservableCollection<FakeDatabase>();List<FakeDatabase> result = _source.Take(20).ToList();_fakeSoruce.Clear();_fakeSoruce.AddRange(result);_firstPageCommand = new DelegateCommand(FirstPageAction);_previousPageCommand = new DelegateCommand(PreviousPageAction);_nextPageCommand = new DelegateCommand(NextPageAction);_lastPageCommand = new DelegateCommand(LastPageAction);}private void FirstPageAction(){CurrentPage = 1;var result = _source.Take(_pageSize).ToList();_fakeSoruce.Clear();_fakeSoruce.AddRange(result);}private void PreviousPageAction(){if(CurrentPage == 1){return;}List<FakeDatabase> result = new List<FakeDatabase>();if(CurrentPage == 2){result = _source.Take(_pageSize).ToList();}else{result = _source.Skip((CurrentPage - 2) * _pageSize).Take(_pageSize).ToList();}_fakeSoruce.Clear();_fakeSoruce.AddRange(result);CurrentPage--;}private void NextPageAction(){if(CurrentPage == _totalPage){return;}List<FakeDatabase> result = new List<FakeDatabase>();result = _source.Skip(CurrentPage * _pageSize).Take(_pageSize).ToList();_fakeSoruce.Clear();_fakeSoruce.AddRange(result);CurrentPage++;}private void LastPageAction(){CurrentPage = TotalPage;int skipCount = (_totalPage - 1) * _pageSize;int takeCount = _source.Count - skipCount;var result = _source.Skip(skipCount).Take(takeCount).ToList();_fakeSoruce.Clear();_fakeSoruce.AddRange(result);}}
綁定到UI的數據源只是需要顯示的數據,不會把所有數據都取出來。當選擇顯示頁數時,只需要將新的數據源附上即可。
總結:如果需要對該分頁控件進行擴展,例如,增加每頁顯示條數功能,只需要在Pager控件中增加相應的依賴屬性即可。
感謝您的閱讀,代碼點擊這里下載。