基于WPF系统框架设计(10)-分页控件设计
背景
最近要求项目组成员开发一个通用的分页组件,要求是这个组件简单易用,通用性,兼容现有框架MVVM模式,可是最后给我提交的成果勉强能够用,却欠少灵活性和框架兼容性。
设计的基本思想
传入数据源,总页数,当前页码,每页记录数,达到分页显示数据的功能。
优化
我把原本不支持MVVM的源码改善了一下,可能还可以再优化得好些,支持MVVM模式,较果如下图:
添加一解决方案:TLAgent.Pager
- 设计DataPager类,继承UserControl, INotifyPropertyChanged ,参考如下代码:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Input;
- using System.ComponentModel;
- namespace TLAgent.Pager {
- /// <summary>
- /// DataPager.xaml 的交互逻辑
- /// </summary>
- public partial class DataPager : UserControl, INotifyPropertyChanged {
- public DataPager() {
- InitializeComponent();
- }
- #region 依赖属性和事件
- public int PageSize {
- get { return (int)GetValue(PageSizeProperty); }
- set { SetValue(PageSizeProperty, value); }
- }
- // Using a DependencyProperty as the backing store for PageSize. This enables animation, styling, binding, etc...
- public static readonly DependencyProperty PageSizeProperty =
- DependencyProperty.Register("PageSize", typeof(int), typeof(DataPager), new UIPropertyMetadata(10));
- public int Total {
- get { return (int)GetValue(TotalProperty); }
- set { SetValue(TotalProperty, value); }
- }
- // Using a DependencyProperty as the backing store for Total. This enables animation, styling, binding, etc...
- public static readonly DependencyProperty TotalProperty =
- DependencyProperty.Register("Total", typeof(int), typeof(DataPager), new UIPropertyMetadata(0));
- public int PageIndex {
- get { return (int)GetValue(PageIndexProperty); }
- set { SetValue(PageIndexProperty, value); }
- }
- // Using a DependencyProperty as the backing store for PageIndex. This enables animation, styling, binding, etc...
- public static readonly DependencyProperty PageIndexProperty =
- DependencyProperty.Register("PageIndex", typeof(int), typeof(DataPager), new UIPropertyMetadata(1));
- public string PageSizeList {
- get { return (string)GetValue(PageSizeListProperty); }
- set { SetValue(PageSizeListProperty, value); }
- }
- // Using a DependencyProperty as the backing store for PageSizeList. This enables animation, styling, binding, etc...
- public static readonly DependencyProperty PageSizeListProperty =
- DependencyProperty.Register("PageSizeList", typeof(string), typeof(DataPager), new UIPropertyMetadata("5,10,20", (s, e) => {
- DataPager dp = s as DataPager;
- if (dp.PageSizeItems == null) dp.PageSizeItems = new List<int>();
- else dp.PageSizeItems.Clear();
- dp.RaisePropertyChanged("PageSizeItems");
- }));
- public IEnumerable<object> ItemsSource {
- get { return (IEnumerable<object>)GetValue(ItemsSourceProperty); }
- set { SetValue(ItemsSourceProperty, value); }
- }
- /// <summary>
- /// ItemsSource数据源
- /// </summary>
- public static DependencyProperty ItemsSourceProperty =
- DependencyProperty.Register("ItemsSource", typeof(IEnumerable<object>), typeof(DataPager), new UIPropertyMetadata(null));
- public static readonly RoutedEvent PageChangedEvent = EventManager.RegisterRoutedEvent("PageChanged", RoutingStrategy.Bubble, typeof(PageChangedEventHandler), typeof(DataPager));
- /// <summary>
- /// 分页更改事件
- /// </summary>
- public event PageChangedEventHandler PageChanged {
- add {
- AddHandler(PageChangedEvent, value);
- }
- remove {
- RemoveHandler(PageChangedEvent, value);
- }
- }
- #endregion
- public ICommand PageChangedCommand { get; set; }
- #region 通知属性
- private List<int> _pageSizeItems;
- /// <summary>
- /// 显示每页记录数集合
- /// </summary>
- public List<int> PageSizeItems {
- get {
- if (_pageSizeItems == null) {
- _pageSizeItems = new List<int>();
- }
- if (PageSizeList != null) {
- List<string> strs = PageSizeList.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
- _pageSizeItems.Clear();
- strs.ForEach(c => {
- _pageSizeItems.Add(Convert.ToInt32(c));
- });
- }
- return _pageSizeItems;
- }
- set {
- if (_pageSizeItems != value) {
- _pageSizeItems = value;
- RaisePropertyChanged("PageSizeItems");
- }
- }
- }
- private int _pageCount;
- /// <summary>
- /// 总页数
- /// </summary>
- public int PageCount {
- get { return _pageCount; }
- set {
- if (_pageCount != value) {
- _pageCount = value;
- RaisePropertyChanged("PageCount");
- }
- }
- }
- private int _start;
- /// <summary>
- /// 开始记录数
- /// </summary>
- public int Start {
- get { return _start; }
- set {
- if (_start != value) {
- _start = value;
- RaisePropertyChanged("Start");
- }
- }
- }
- private int _end;
- /// <summary>
- /// 结束记录数
- /// </summary>
- public int End {
- get { return _end; }
- set {
- if (_end != value) {
- _end = value;
- RaisePropertyChanged("End");
- }
- }
- }
- public event PropertyChangedEventHandler PropertyChanged;
- public void RaisePropertyChanged(string propertyName) {
- if (PropertyChanged != null) {
- PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
- }
- }
- #endregion
- #region 字段、属性、委托
- public delegate void PageChangedEventHandler(object sender, PageChangedEventArgs args);
- private PageChangedEventArgs pageChangedEventArgs;
- #endregion
- #region 引发分页更改事件
- /// <summary>
- /// 引发分页更改事件
- /// </summary>
- private void RaisePageChanged() {
- if (pageChangedEventArgs == null) {
- pageChangedEventArgs = new PageChangedEventArgs(PageChangedEvent, PageSize, PageIndex);
- } else {
- pageChangedEventArgs.PageSize = this.PageSize;
- pageChangedEventArgs.PageIndex = this.PageIndex;
- }
- RaiseEvent(pageChangedEventArgs);
- //calc start、end
- if (ItemsSource != null) {
- int curCount = ItemsSource.Count();
- Start = (PageIndex - 1) * PageSize + 1;
- End = Start + curCount - 1;
- if (Total % PageSize != 0) {
- PageCount = Total / PageSize + 1;
- } else {
- PageCount = Total / PageSize;
- }
- } else {
- Start = End = PageCount = Total = 0;
- }
- //调整图片的显示
- btnFirst.IsEnabled = btnPrev.IsEnabled = (PageIndex != 1);
- btnNext.IsEnabled = btnLast.IsEnabled = (PageIndex != PageCount);
- }
- #endregion
- #region 分页操作事件
- void DataPager_Loaded(object sender, RoutedEventArgs e) {
- RaisePageChanged();
- }
- private void cbpPageSize_SelectionChanged(object sender, SelectionChangedEventArgs e) {
- if (this.IsLoaded) {
- PageSize = (int)cboPageSize.SelectedItem;
- RaisePageChanged();
- }
- }
- private void btnFirst_Click(object sender, RoutedEventArgs e) {
- PageIndex = 1;
- RaisePageChanged();
- }
- private void btnPrev_Click(object sender, RoutedEventArgs e) {
- if (PageIndex > 1) {
- --PageIndex;
- }
- RaisePageChanged();
- }
- private void btnNext_Click(object sender, RoutedEventArgs e) {
- if (Total % PageSize != 0) {
- PageCount = Total / PageSize + 1;
- } else {
- PageCount = Total / PageSize;
- }
- if (PageIndex < PageCount) {
- ++PageIndex;
- }
- RaisePageChanged();
- }
- private void btnLast_Click(object sender, RoutedEventArgs e) {
- if (Total % PageSize != 0) {
- PageCount = Total / PageSize + 1;
- } else {
- PageCount = Total / PageSize;
- }
- PageIndex = PageCount;
- RaisePageChanged();
- }
- private void btnRefresh_Click(object sender, RoutedEventArgs e) {
- RaisePageChanged();
- }
- private void tbPageIndex_PreviewKeyDown(object sender, KeyEventArgs e) {
- if (e.Key == Key.Enter) {
- tbPageIndex_LostFocus(sender, null);
- }
- }
- private void tbPageIndex_LostFocus(object sender, RoutedEventArgs e) {
- int pIndex = 0;
- try {
- pIndex = Convert.ToInt32(tbPageIndex.Text);
- } catch { pIndex = 1; }
- if (pIndex < 1) PageIndex = 1;
- else if (pIndex > PageCount) PageIndex = PageCount;
- else PageIndex = pIndex;
- RaisePageChanged();
- }
- #endregion
- }
- /// <summary>
- /// 分页更改参数
- /// </summary>
- public class PageChangedEventArgs : RoutedEventArgs {
- public int PageSize { get; set; }
- public int PageIndex { get; set; }
- public PageChangedEventArgs(RoutedEvent routeEvent, int pageSize, int pageIndex)
- : base(routeEvent) {
- this.PageSize = pageSize;
- this.PageIndex = pageIndex;
- }
- }
- }
- 添加一支持泛型类,可以传入任何类型对象
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Linq;
- using System.Text;
- namespace TLAgent.Pager
- {
- public class DataResult<T> : INotifyPropertyChanged
- {
- public int _total;
- public int Total
- {
- get
- {
- return _total;
- }
- set
- {
- if (_total != value)
- {
- _total = value;
- RaisePropertyChanged("Total");
- }
- }
- }
- private List<T> _dataSource;
- public List<T> DataSource
- {
- get
- {
- return _dataSource;
- }
- set
- {
- if (_dataSource != value)
- {
- _dataSource = value;
- RaisePropertyChanged("DataSource");
- }
- }
- }
- public DataResult()
- {
- DataSource = new List<T>();
- }
- public void RaisePropertyChanged(string propertyName)
- {
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
- }
- }
- public event PropertyChangedEventHandler PropertyChanged;
- }
- }
测试
添加一个测试项目:TLAgent.Pager.Test
- 自定义一个命令InteractiveCommand,支持传入参数,代码参考:
- // -----------------------------------------------------------------------
- // <copyright file="InteractiveCommand.cs" company="M&M">
- // TODO: Update copyright text.
- // </copyright>
- // -----------------------------------------------------------------------
- namespace TLAgent.Pager.Test
- {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Windows;
- using System.Windows.Input;
- using System.Windows.Interactivity;
- using System.Reflection;
- /// <summary>
- /// TODO: Update summary.
- /// </summary>
- public class InteractiveCommand : TriggerAction<DependencyObject>
- {
- protected override void Invoke(object parameter)
- {
- if (base.AssociatedObject != null)
- {
- ICommand command = this.ResolveCommand();
- object[] tempObj = { parameter, CommandParameter };
- if ((command != null) && command.CanExecute(tempObj))
- {
- command.Execute(tempObj);
- }
- }
- }
- public object CommandParameter
- {
- get { return GetValue(CommandParameterProperty); }
- set { SetValue(CommandParameterProperty, value); }
- }
- public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register
- ("CommandParameter", typeof(object), typeof(InteractiveCommand), new PropertyMetadata(null, OnCommandParameterChanged));
- private static void OnCommandParameterChanged
- (DependencyObject sender, DependencyPropertyChangedEventArgs e)
- {
- InteractiveCommand ic = sender as InteractiveCommand;
- if (ic != null)
- {
- ic.SynchronizeElementState();
- }
- }
- private void SynchronizeElementState()
- {
- ICommand command = Command;
- if (command != null)
- {
- FrameworkElement associatedObject = AssociatedObject as FrameworkElement;
- if (associatedObject != null)
- {
- associatedObject.IsEnabled = command.CanExecute(CommandParameter);
- }
- }
- }
- private ICommand ResolveCommand()
- {
- ICommand command = null;
- if (this.Command != null)
- {
- return this.Command;
- }
- if (base.AssociatedObject != null)
- {
- foreach (PropertyInfo info in base.AssociatedObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
- {
- if (typeof(ICommand).IsAssignableFrom(info.PropertyType) && string.Equals(info.Name, this.CommandName, StringComparison.Ordinal))
- {
- command = (ICommand)info.GetValue(base.AssociatedObject, null);
- }
- }
- }
- return command;
- }
- private string commandName;
- public string CommandName
- {
- get
- {
- base.ReadPreamble();
- return this.commandName;
- }
- set
- {
- if (this.CommandName != value)
- {
- base.WritePreamble();
- this.commandName = value;
- base.WritePostscript();
- }
- }
- }
- #region Command
- public ICommand Command
- {
- get { return (ICommand)GetValue(CommandProperty); }
- set { SetValue(CommandProperty, value); }
- }
- public static readonly DependencyProperty CommandProperty =
- DependencyProperty.Register("Command", typeof(ICommand), typeof(InteractiveCommand), new UIPropertyMetadata(null));
- #endregion
- }
- }
在MainWindow.xaml中,添一DataGrid和一个DataPager,参考如下代码:
- <Window x:Class="TLAgent.Pager.Test.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:lib="clr-namespace:TLAgent.Pager;assembly=TLAgent.Pager"
- xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
- xmlns:cmd="clr-namespace:TLAgent.Pager.Test"
- xmlns:viewModels="clr-namespace:TLAgent.Pager.Test.ViewModels"
- Name="self"
- Title="MainWindow" Height="350" Width="525">
- <Window.DataContext>
- <viewModels:MainWindowViewModel/>
- </Window.DataContext>
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="*" />
- <RowDefinition Height="Auto" />
- </Grid.RowDefinitions>
- <DataGrid ItemsSource="{Binding Path=ItemsSource,ElementName=dataPager}">
- <!--<DataGrid.Columns>
- <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
- <DataGridTextColumn Header="Age" Binding="{Binding Age}" />
- <DataGridTextColumn Header="Gender" Binding="{Binding Gender}" />
- </DataGrid.Columns>-->
- </DataGrid>
- <lib:DataPager Grid.Row="1" Name="dataPager" PageSizeList="10,20,30,50"
- ItemsSource="{Binding Result.DataSource,Mode=TwoWay}"
- Total="{Binding Result.Total,Mode=TwoWay}"
- >
- <i:Interaction.Triggers>
- <i:EventTrigger EventName="PageChanged">
- <cmd:InteractiveCommand Command="{Binding PageChangedCommand}" CommandName="PageChangedCommand"/>
- </i:EventTrigger>
- </i:Interaction.Triggers>
- </lib:DataPager>
- </Grid>
- </Window>
添加一个ViewModel:MainWindowViewModel,继承NotificationObject:
- using System.Collections.Generic;
- using System.Linq;
- using System.Windows.Input;
- using Microsoft.Practices.Prism.Commands;
- using Microsoft.Practices.Prism.ViewModel;
- namespace TLAgent.Pager.Test.ViewModels
- {
- public class MainWindowViewModel : NotificationObject
- {
- private DelegateCommand<object[]> _commandWithEventArgs;
- public List<Student> _dataSource;//声明数据
- public MainWindowViewModel()
- {
- Result = new DataResult<Student>();//此处Student可以传入任何数据类型
- _dataSource = Controller.GetData();//获取得数据
- Result.DataSource = _dataSource;//给数据源赋值
- Query(10, 1);
- }
- private DataResult<Student> _result;
- public DataResult<Student> Result//公开给View作数据源绑定
- {
- get { return _result; }
- set
- {
- _result = value;
- RaisePropertyChanged("Result");
- }
- }
- public void Query(int size, int pageIndex)
- {
- Result.Total = _dataSource.Count;//给页总数赋值
- Result.DataSource = _dataSource.Skip((pageIndex - 1) * size).Take(size).ToList();//改变数据源赋值
- }
- /// <summary>
- ///
- /// </summary>
- public ICommand PageChangedCommand
- {
- get { return _commandWithEventArgs ?? (_commandWithEventArgs = new DelegateCommand<object[]>(ShowData)); }
- }
- private void ShowData(object[] objParam)
- {
- PageChangedEventArgs args = (PageChangedEventArgs)objParam[0];//View把PageChangedEventArgs事件传过来,此事件带来页码和页序号
- Query(args.PageSize, args.PageIndex);
- }
- }
- }
添加一个Controller类,从此类中获取测试数据来源:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace TLAgent.Pager.Test
- {
- public class Controller
- {
- public static List<Student> GetData()
- {
- List<Student> Students;
- Students = new List<Student>();
- Random random = new Random();
- int count = random.Next(20, 200);
- for (int i = 1; i <= count; i++)
- {
- Student stu = new Student
- {
- Name = "Name" + i,
- Age = random.Next(20, 50),
- Gender = (i % 3 != 0),
- Desc = "Desc " + i,
- };
- Students.Add(stu);
- }
- return Students;
- }
- }
- }
添加一个Student类,只是作为测试用,项目中可以按实际需要,DataResult<T>是支持多种类型的数据。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Microsoft.Practices.Prism.ViewModel;
- namespace TLAgent.Pager.Test {
- public class Student : NotificationObject
- {
- public string Name { get; set; }
- public int Age { get; set; }
- public bool Gender { get; set; }
- public string Desc { get; set; }
- }
- }
到此一个分页控件设计就完成了,在此做一些总结。
基于WPF系统框架设计(10)-分页控件设计的更多相关文章
- 基于WPF系统框架设计(5)-Ribbon整合Avalondock 2.0实现多文档界面设计(二)
AvalonDock 是一个.NET库,用于在停靠模式布局(docking)中排列一系列WPF/WinForm控件.最新发布的版本原生支持MVVM框架.Aero Snap特效并具有更好的性能. Ava ...
- 基于avalon+jquery做的bootstrap分页控件
刚开始学习avalon,项目需要就尝试写了个分页控件Pager.js:基于BootStrap样式这个大家都很熟悉 在这里推荐下国产前端神器avalon:确实好用,帮我解决了很多前端问题. 不多说了,代 ...
- WPF自定义控件与样式(10)-进度控件ProcessBar自定义样
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: Pro ...
- 基于WPF系统框架设计(4)-Ribbon整合Avalondock 2.0实现多文档界面设计(一)
前些时间研究了WPF的一些框架,感觉基于Prism框架的MVVM模式对系统的UI与逻辑分离很好,所以就按照之前Winform的框架设计,用WPF做了一套,感觉比Winform要强很多. MVVM模式和 ...
- 基于WPF系统框架设计(6)-整合MVVM框架(Prism)
应用场景 我们基础的框架已经搭建起来了,现在整合MVVM框架Prism,在ViewModel做一些逻辑处理,真正把界面设计分离出来. 这样方便我们系统开发分工合作,同时提高系统可维护性和灵活性. 具体 ...
- 基于WPF系统框架设计(8)-PasswordBox传值到ViewMode
应用场景 我要做一个系统登录功能,需要传用户名和密码到ViewModel中,可是PasswordBox传值到ViewModel中好像跟TextBox等控件不一样.这里需要用到附加属性. 附加属性:一个 ...
- 基于WPF系统框架设计(7)-TextBox/PasswordBox在ViewModel中支持回车命令
应用场景 我现在做一个系统登录功能,要求在PasswordBox上输完密码后回车,能够响应Enter事件,并执行ViewModel中对应的方法.如果登录成功则隐藏当前窗口显示主窗体,登录失败则焦点返回 ...
- 基于WPF系统框架设计(3)-Fluent Ribbon界面布局
一个系统框架除了功能菜单导航,有系统内容显示区域,系统状态栏. Silver: Blue: Black: 系统界面设计,就不进行技术细节介绍了,主题以框架设计为主,Xaml源码参考: <Flue ...
- 基于WPF系统框架设计(9)-多值绑定之IMultiValueConverter
应用场景 我想把View层的一个布局控件和功能按钮传到ViewModel层,达到动态变更布局,同时灵活获取功能按钮的属性,让View和ViewModel完全分离,而不受View层影响. 最后我想到使用 ...
随机推荐
- mysql 分组查询前n条数据
今天去面试,碰到一道面试题: 有一个学生成绩表,表中有 表id.学生名.学科.分数.学生id .查询每科学习最好的两名学生的信息: 建表sql: CREATE TABLE `stuscore` ( ` ...
- vim的常用操作
vim的几种编辑模式 正常模式:可以使用快捷键命令,或按:输入命令行. 插入模式:可以输入文本,在正常模式下,按i.a.o等都可以进入插入模式. 可视模式:正常模式下按v可以进入可视模式, 在可视 ...
- IOS开发---菜鸟学习之路--(三)-数据解析
第三篇 上一篇我们讲了如何通过NSURL类来获取数据, 这一章我们来讲下对于获取过来的数据如何解析. 好了直接进入正文吧. 正文: 上一篇讲了 我们获取过来的数据格式是JSON格式的 大家可以搜下对应 ...
- IOS开发学习笔记023-UIToolBar的使用
这里使用代码实现 大概过程: 1.创建工具条 2.创建插入条 3.添加头像.标签.删除按钮 4.点击头像获取标签信息 做一个简单的联系人列表,可以添加删除联系人,现在还没有添加头像和文字,接下来慢慢添 ...
- RESTful-rest_framework视图层-第三篇
图书管理系统: 实现图书接口的增.删.改.查 方式一:普通的方式 views配置: #Book的增.删.改.查接口 class BookSerializer(serializers.ModelSeri ...
- [问题解决]docker启动不了
问题描述:昨天下午整合了同事的代码,发现docker启动好后,docker ps查看不到,docker ps -a发现docker容器没有启动. 尝试多次启动发现都是启动不了. 经过搜索发现 http ...
- 设计模式(一)单例模式:2-懒汉模式(Lazy)
思想: 相比于饿汉模式,懒汉模式实际中的应用更多,因为在系统中,“被用到时再初始化”是更佳的解决方案. 设计思想与饿汉模式类似,同样是持有一个自身的引用,只是将 new 的动作延迟到 getinsta ...
- NOIP试题解析
NOIP试题解析 by QTY_YTQ noip2010关押罪犯(并查集) 题意是有n个罪犯关在两个监狱中,其中有m对罪犯有仇恨关系,如果有仇恨的罪犯关在一起会产生一定影响力的事件 ...
- gcc编译生成静态及动态链接库步骤
gcc编译生成静态及动态链接库步骤 这两天在看<Linux C程序设计大全>,吴岳编著,清华大学出版社.这本书是在一个培训机构看到的,在网上查了下该书的相关信息.从目录而言,该书涵盖了Li ...
- input[type="radio"]自定义样式
input为radio时,虽然会有默认选中的样式,但是并不符合大多数项目的需求,我们的目标是可以随心所欲自定义它的样式.怎么做呢?其实很简单,只要抓住3点.分别是1.label 2.隐藏自带样式 3. ...