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

背景

最近要求项目组成员开发一个通用的分页组件,要求是这个组件简单易用,通用性,兼容现有框架MVVM模式,可是最后给我提交的成果勉强能够用,却欠少灵活性和框架兼容性。

设计的基本思想

传入数据源,总页数,当前页码,每页记录数,达到分页显示数据的功能。

优化

我把原本不支持MVVM的源码改善了一下,可能还可以再优化得好些,支持MVVM模式,较果如下图:

image

添加一解决方案:TLAgent.Pager

image

  • 设计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

image

  • 自定义一个命令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)