自定义WPF分页控件
一、分页控件功能说明
实现如上图所示的分页控件,需要实现一下几个功能:
- 可以设置每页能够展示的最大列数(例如每页8列、每页16列等等)。
- 加载的数组总数量超过设置的每页列数后,需分页展示。
- 可以直接点击指定的列数或者上下页按钮进行页面跳转
二、自定义分页控件使用说明
为了实现以上功能,主要进行以下工作:
1、添加一个自定义按钮PagerButton类,声明一个依赖属性IsActive,用于记录当前页面所在页数的按钮,此时该按钮边框高亮显示,具体代码如下:
public class PagerButton : Button
{
public bool IsActive
{
get { return (bool)GetValue(IsActiveProperty); }
set { SetValue(IsActiveProperty, value); }
}
public static readonly DependencyProperty IsActiveProperty =
DependencyProperty.Register("IsActive", typeof(bool), typeof(PagerButton), new PropertyMetadata(false));
}
<Style x:Key="PagerButtonStyle" TargetType="controls:PagerButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:PagerButton">
<Border x:Name="b1" CornerRadius="2" Background="{StaticResource Themes}"
BorderThickness="1" BorderBrush="{StaticResource Disabled}"
Width="32" Height="32" Margin="4,0">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="b1" Property="BorderBrush" Value="{StaticResource Accent}"></Setter>
</Trigger>
<Trigger Property="IsActive" Value="True">
<Setter TargetName="b1" Property="BorderBrush" Value="{StaticResource Accent}"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
2、添加自定义分页控件PagerBar类,用于展示分页按钮(使用PagerButton类)和实现分页跳转,需要定义当前页面、总页数、设置的每页最大列数三个依赖属性,具体如下:
public int CurrentPageIndex
{
get { return (int)GetValue(CurrentPageIndexProperty); }
set { SetValue(CurrentPageIndexProperty, value); }
}
public int PageSize
{
get { return (int)GetValue(PageSizeProperty); }
set { SetValue(PageSizeProperty, value); }
}
public int PageCount
{
get { return (int)GetValue(PageCountProperty); }
set { SetValue(PageCountProperty, value); }
}
public static readonly DependencyProperty CurrentPageIndexProperty = DependencyProperty.Register("CurrentPageIndex", typeof(int), typeof(PagerBar), new PropertyMetadata(-1, CurrentPageIndexPropertyChangedCallback));
public static readonly DependencyProperty PageSizeProperty = DependencyProperty.Register("PageSize", typeof(int), typeof(PagerBar), new PropertyMetadata(10, PageSizePropertyChangedCallback));
public static readonly DependencyProperty PageCountProperty = DependencyProperty.Register("PageCount", typeof(int), typeof(PagerBar), new PropertyMetadata(-1, PageCountPropertyChangedCallback));
3、添加一个工具类Pager,用于将数据按照要求分页,该工具类声明当前页数、总页数、设置的每页最大列数三个属性,具体如下:
public int PageSize
{
get => _pageSize;
set
{
if (value == _pageSize)
return;
_pageSize = value;
OnPropertyChanged();
SetPageSize(_pageSize);
}
}
public int PageCount
{
get => _pageCount;
set
{
if (value == _pageCount)
return;
_pageCount = value;
// 最少页为1页
if (_pageCount == 0)
_pageCount = 1;
OnPropertyChanged();
}
}
public int CurPageIndex
{
get => _curPageIndex;
set
{
if (value == _curPageIndex)
return;
_curPageIndex = value;
OnPropertyChanged();
GotoPageOf(_curPageIndex);
}
}
4、将Pager类和PageBar控件进行数据绑定。具体操作为:在绑定的ViewModel上声明一个Pager类,然后将该Pager类的属性和PagrBar进行一一对应绑定。具体代码如下:
<controls:PagerBar Grid.Row="1" Margin="5"
HorizontalAlignment="Center"
PageSize="{Binding Path=Pager.PageSize, Mode=TwoWay}"
PageCount="{Binding Path=Pager.PageCount, Mode=TwoWay}"
CurrentPageIndex="{Binding Path=Pager.CurPageIndex, Mode=TwoWay}"></controls:PagerBar>
5、初始化Pager类时,在界面绑定的ViewModel里面重新声明一个数组,用于保存分页后的数组,将该数组绑定到待展示的条目控件(例如ListBox)上,具体如下:
StudentCollection=new ObservableCollection<Student>();
for (int i = 0; i < 10; i++)
{
StudentCollection.Add(new Student()
{
Id = Index = i,
Source = 10 * (i + 1),
});
}
AddCommand =new RelayCommand(ExecuteAddCommand);
DeleteCommand=new RelayCommand(ExecuteDeleteCommand);
SortCommand=new RelayCommand(ExecuteSortCommand);
Pager=new Pager<Student>(8,StudentCollection);
Pager.PagerUpdated += items =>
{
StudentCollectionPaging = new ObservableCollection<Student>(items);
};
Pager.CurPageIndex = 1;
<ListBox x:Name="ListBoxStudent" Grid.Row="0"
ItemsSource="{Binding StudentCollectionPaging}"
ItemTemplate="{StaticResource StudentDateTemplate}"></ListBox>
三、总结说明
为了实现绑定的数组添加、删除时,PageBar分组控件也能立即更新控件,Pager工具类增加以下构造函数,首先保证数组为同一引用,其次使用ObservableCollection保证界面和ViewModel即时更新:
public Pager(int pageSize, ObservableCollection<T> source)
{
_pageSize = pageSize;
_itemsSource = source;
_itemsSource.CollectionChanged += ItemsSourceOnCollectionChanged;
CalculatePaging();
}
private void ItemsSourceOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
CalculatePaging();
GotoPageOf(CurPageIndex);
}
四、示例源码
示例源码地址:分页控件源码
五、问题
在实际应用中,发现如下问题:当需要对绑定的整个数组进行排序时,由于Pager类初始化传入的数组必须和实际数为同一个引用且必须为ObservableCollection数组,那么使用LINQ排序完成后,必须要使用ToList进行转换,就必须重新初始化ObservableCollection,那么后续当该ObservableCollection数组变化时,也无法通知到Pager类的数组了。为了解决该问题,想到以下两个方法:
(1)自定义排序,针对ObservableCollection的每个数组对象进行排序。这样排序完成后ObservableCollection引用无变化。
(2)先用临时变量保存排序完成的数组,然后清空ObservableCollection,然后再迭代添加临时数组。如此,ObservableCollection对象前后也为统一引用。
public ICommand SortCommand { get; set; }
private void ExecuteSortCommand(object obj)
{
var list = StudentCollection.ToList().OrderByDescending(item=>item.Source).ToList();
StudentCollection.Clear();
foreach (var item in list)
{
StudentCollection.Add(item);
}
}
目前暂时采用了第二种方法,但该方法效率不高。后续有更好的解决方法可以留言讨论。
自定义WPF分页控件的更多相关文章
- 示例:自定义WPF底层控件UI库 HeBianGu.General.WpfControlLib V2.0版本
原文:示例:自定义WPF底层控件UI库 HeBianGu.General.WpfControlLib V2.0版本 一.目的:封装了一些控件到自定义的控件库中,方便快速开发 二.实现功能: 基本实现常 ...
- WPF 分页控件 WPF 多线程 BackgroundWorker
WPF 分页控件 WPF 多线程 BackgroundWorker 大家好,好久没有发表一篇像样的博客了,最近的开发实在头疼,很多东西无从下口,需求没完没了,更要命的是公司的开发从来不走正规流程啊, ...
- 两款不同应用场景的Wpf分页控件
简介 今天给大家分享两个Wpf分页控件,本篇博客主要介绍一些实现思路和使用方法,具体实现和应用代码请参考文末的Demo链接 废话不多说,先看一下效果~ (两款控件显示效果是一样的) 实现思路 一款控件 ...
- WPF自定义DataGrid分页控件
新建Custom Control,名:PagingDataGrid 打开工程下面的Themes\Generic.xaml xaml里面代码替换如下 <Style x:Key="{x:T ...
- 自定义angularjs分页控件
继昨天写了knockoutjs+ jquery pagination+asp.net web Api 实现无刷新列表页 ,正好最近刚学习angularjs ,故琢磨着写一个angularjs版本的分页 ...
- [转]Oracle分页之二:自定义web分页控件的封装
本文转自:http://www.cnblogs.com/scy251147/archive/2011/04/16/2018326.html 上节中,讲述的就是Oracle存储过程分页的使用方式,但是如 ...
- C# WinForm自定义通用分页控件
大家好,前几天因工作需要要开发一个基于WinForm的小程序.其中要用到分页,最开始的想法找个第三方的dll用一下,但是后来想了想觉得不如自己写一个玩一下 之前的web开发中有各式各样的列表组件基本都 ...
- WPF 分页控件的实现 -用户控件
效果图:
- WPF 分页控件Pager
本文为伪原创原文为 NET未来之路的https://www.cnblogs.com/lonelyxmas/p/10641255.html 原文中,页码数量会不断增加,会将下一页的按钮顶出去 修改了一下 ...
随机推荐
- IPFS挖矿赚钱吗?IPFS挖矿是真的吗?
IPFS一出现就获得了极高的关注度,「让人类信息永存」的口号也让其蒙上了一层神秘的面纱.今天我就来给大家自剖析,一探IPFS技术的真相. IPFS是一个去中心化存储网络,而Filecoin是IPFS激 ...
- 推荐一款全能测试开发神器:Mockoon!1分钟快速上手!
1. 说一下背景 在日常开发或者测试工作中,经常会因为下游服务不可用或者不稳定时,通过工具或者技术手段去模拟一个HTTP Server,或者模拟所需要的接口数据. 这个时候,很多人脑海里,都会想到可以 ...
- TypeError: Can't convert 'int' object to str implicitly Python常见错误
尝试连接非字符串值与字符串 想要字符串连接非字符串需要先进行强制转化 可以用str()函数 --------------------------------
- MySQL常见的七种锁详细介绍()
原地址: https://blog.csdn.net/Saintyyu/article/details/91269087
- OO第四单元&课程总结
一.本单元架构设计 第一次作业 本次作业要求解析UML类图. 首先,将UML中的各个元素(比如UmlClass.UmlInterface等)转化成自己定义的类(MyClass.MyInterface) ...
- 周爱民带你深入剖析JavaScript核心原理
作为前端工程师必备技能,JavaScript 的重要性不言而喻.虽然易上手,但却有着诸多复杂微妙的机制,想要真正掌握绝非易事. 专栏面向JavaScript语言的实际应用者与深度爱好者,以讲述Java ...
- MySQL实战45讲,丁奇带你搞懂
之前,你大概都是通过搜索别人的经验来解决问题.如果能够理解MySQL的工作原理,那么在遇到问题的时候,是不是就能更快地直戳问题的本质? 以实战中的常见问题为切入点,带你剖析现象背后的本质原因.为你串起 ...
- ES6转ES5(Babel转码器)
ES6转ES5(Babel转码器) 前提:必须在VScode中已经安装了Node.js 官网:https://nodejs.org/en/ 一.安装命令行转码工具 npm install --glob ...
- 自动化kolla-ansible部署centos7.9+openstack-train-超融合高可用架构
自动化kolla-ansible部署centos7.9+openstack-train-超融合高可用架构 欢迎加QQ群:1026880196 进行交流学习 环境说明: 1. 满足一台电脑一个网卡的环境 ...
- 谈谈react hooks的优缺点
前言Hook 是 React 16.8 的新增特性.它是完全可选的,并且100%向后兼容.它可以让你使用函数组件的方式,运用类组件以及 react 其他的一些特性,比如管理状态.生命周期钩子等.从概念 ...