在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控件中增加相应的依赖属性即可。

感谢您的阅读,代码点击这里下载。

WPF 实现 DataGrid/ListView 分页控件的更多相关文章

  1. WPF最简单的分页控件

    背景:最近在写项目的时候需要写一个简单的分页功能,因项目需要,没有改为MVVM模式,只需要在后台实现 1.呈现效果如下: 接下来就来上代码,看看怎么实现的 1.界面代码 <StackPanel ...

  2. WPF自定义DataGrid分页控件

    新建Custom Control,名:PagingDataGrid 打开工程下面的Themes\Generic.xaml xaml里面代码替换如下 <Style x:Key="{x:T ...

  3. 两款不同应用场景的Wpf分页控件

    简介 今天给大家分享两个Wpf分页控件,本篇博客主要介绍一些实现思路和使用方法,具体实现和应用代码请参考文末的Demo链接 废话不多说,先看一下效果~ (两款控件显示效果是一样的) 实现思路 一款控件 ...

  4. ASP.NET使用ListView数据绑定控件和DataPager实现数据分页显示(一)

    为什么使用ListView+DataPager的方式实现分页显示? .net提供的诸多数据绑定控件,每一种都有它自己的优点和缺点.如果需要对数据进行操作,如果数据量不大的情况下,DataList和Gr ...

  5. WPF 分页控件 WPF 多线程 BackgroundWorker

    WPF 分页控件 WPF 多线程 BackgroundWorker 大家好,好久没有发表一篇像样的博客了,最近的开发实在头疼,很多东西无从下口,需求没完没了,更要命的是公司的开发从来不走正规流程啊, ...

  6. WPF管理系统自定义分页控件 - WPF特工队内部资料

    最近做一个演示的管理系统项目,需要用到分页控件,在网上找了很多,依然找到与UI模版匹配的,最后干脆自己写一个. 分页控件分析: 1.分页控件分简单显示和复杂显示两种: 2.包含上一页.下一页以及页码明 ...

  7. WPF 分页控件的实现 -用户控件

    效果图:

  8. WPF自定义分页控件,样式自定义,简单易用

    WPF自定义分页控件 做了许久伸手党,终于有机会贡献一波,搜索一下WPF分页控件,还是多,但是不太通用,主要就是样式问题,这个WPF很好解决,还有一个就是分页控件嘛,只关心几个数字的变动就行了,把页码 ...

  9. 基于WPF系统框架设计(10)-分页控件设计

    背景 最近要求项目组成员开发一个通用的分页组件,要求是这个组件简单易用,通用性,兼容现有框架MVVM模式,可是最后给我提交的成果勉强能够用,却欠少灵活性和框架兼容性. 设计的基本思想 传入数据源,总页 ...

随机推荐

  1. UI: 标题栏

    TitleBarDemo.xaml <Page x:Class="Windows10.UI.TitleBarDemo" xmlns="http://schemas. ...

  2. windows下使用vs进行Proctocol Buffer开发(C++篇)

    因工作原因接触Proctocol Buffer(protobuf),至于什么是protobuf,为何使用protobuf,我就不赘述了,百度下都是答案. 今天我介绍的是在windows下使用vs进行p ...

  3. BZOJ 2462: [BeiJing2011]矩阵模板

    2462: [BeiJing2011]矩阵模板 Time Limit: 2 Sec  Memory Limit: 128 MBSubmit: 915  Solved: 432[Submit][Stat ...

  4. JS中匿名函数$(function(){ })和(function(){})()的区别

    “$(function(){ });” Jquery语法的匿名函数,用于存放操作DOM对象的代码,执行其中代码时DOM对象已存在: (通过这样就可以在页面加载完成时通过ajax再异步加载一些数据) “ ...

  5. Android开发笔记之《Window下安装Ubuntu双系统,Grub无法显示Window选项》

    解决方法是: 在terminal里面输入: sudo update-grub 会找到windows的grub 重启电脑就可以了.

  6. Structure And Representation Of MIB Object Names - SNMP Tutorial

    30.8 Structure And Representation Of MIB Object Names We said that ASN.1 specifies how to represent ...

  7. Python调用服务接口

    #! /usr/bin/env python # coding=utf-8 ############################################################## ...

  8. System.Properties和System.getenv区别

    网上很多使用的是getProperties.说获得系统变量,但是其实不正确.getProperties中所谓的"system properties"其实是指"java s ...

  9. 【06-23】js动画学习笔记01

    <html> <head> <style> * { margin:0; padding:0; } #div1{ width:200px; height:200px; ...

  10. [nosql之redis]yum安装redis

    1.首先对于这种nosql来说目前我用到的功能很少,所以感觉没有必要去优化他跟不需要去编译安装.今天来介绍下一个yum安装redis 步骤1:安装扩展yum库 [root@localhost ~]# ...