• 使用MVVM写的WPF分页控件


    首先声明,我是一个小菜鸟,学习WPF也就2个月,如果写的不对的地方,请批评指正。

    因为想做一个WPF分页页面,网上找了很多示例程序,大部分都要求使用存储过称,与业务合在一起,控件的通用性不够强。

    在我看来,分页控件只需要知道数据有多少页、当前是第几页就可以了,上一页、下一页等命令使用事件或者委托发送出去,实现控件与业务的分离。在这里我采用了MVVM模式来实现分页控件,使用MVVM一定要记住:数据驱动UI界面,尽可能不在后台代码中编写业务逻辑和界面逻辑。示例代码使用了Prism,请引用相关DLL。

    首先新建一个自定义控件UserControl

     1 <UserControl x:Class="ZhuanKeWebTool.WPF.Content.UCPager"
     2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     5              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     6              mc:Ignorable="d" 
     7              d:DesignHeight="30" d:DesignWidth="500">
     8     <Grid Background="AliceBlue">
     9         <Grid.ColumnDefinitions>
    10             <ColumnDefinition Width="80" />
    11             <ColumnDefinition Width="*" />
    12             <ColumnDefinition Width="20" />
    13             <ColumnDefinition Width="20" />
    14             <ColumnDefinition Width="Auto" />
    15             <ColumnDefinition Width="20" />
    16             <ColumnDefinition Width="20" />
    17         </Grid.ColumnDefinitions>
    18         <StackPanel Orientation="Horizontal">
    19             <TextBlock Text="" HorizontalAlignment="Left" Height="15" Margin="10,0,0,0"/>
    20             <TextBlock Text="{Binding RecordCount}" VerticalAlignment="Center"/>
    21             <TextBlock Text="" VerticalAlignment="Center"/>
    22         </StackPanel>
    23 
    24         <Button Grid.Column="2" ToolTip="首页" Padding="0" Command="{Binding HomePageCommand}">
    25             <Button.Content>
    26                 <Image Width="12" Source="../Resources/Images/fastrewind.png"/>
    27             </Button.Content>
    28         </Button>
    29         <Button Grid.Column="3" ToolTip="上一页" Padding="0" Command="{Binding PreviousPageCommand}">
    30             <Button.Content>
    31                 <Image Width="12" Source="../Resources/Images/skiprewind.png"/>
    32             </Button.Content>
    33         </Button>
    34 
    35         <WrapPanel Grid.Column="4" HorizontalAlignment="Center" VerticalAlignment="Center">
    36             <TextBlock Text="" VerticalAlignment="Center"/>
    37             <ComboBox ItemsSource="{Binding IndexList}" SelectedItem="{Binding PageIndex}" Width="50"/>
    38             <TextBlock Text="" VerticalAlignment="Center"/>
    39         </WrapPanel>
    40 
    41         <Button Grid.Column="5" ToolTip="下一页" Padding="0" Command="{Binding NextPageCommand}">
    42             <Button.Content>
    43                 <Image Width="12" Source="../Resources/Images/skipforward.png"/>
    44             </Button.Content>
    45         </Button>
    46         <Button Grid.Column="6" ToolTip="尾页" Padding="0" Command="{Binding TailPageCommand}">
    47             <Button.Content>
    48                 <Image Width="12" Source="../Resources/Images/fastforward.png"/>
    49             </Button.Content>
    50         </Button>
    51 
    52     </Grid>
    53 </UserControl>
    View Code

    控件的样子是这样的:

    UserControl的后台代码:

     1 public partial class UCPager : UserControl
     2 {
     3     public UCPagerViewModel UCPagerViewModel { get; private set; }
     4 
     5     public UCPager()
     6     {
     7         InitializeComponent();
     8         UCPagerViewModel = new UCPagerViewModel();
     9         this.DataContext = UCPagerViewModel;
    10     } 
    11 
    12 }

    后台代码很简单,实例化一个ViewModel,把ViewModel作为属性是想让使用者可以更改ViewModel的属性,达到更改分页控件的目的。

    UCPagerViewModel.CS

    /// 申明委托
    /// </summary>
    /// <param name="e"></param>
    /// <returns></returns>
    public delegate void EventPagingHandler(EventPagingArg e);
    
    /// <summary>
    /// 自定义事件参数
    /// </summary>
    public class EventPagingArg : EventArgs
    {
        public int PageIndex { get; set; }
    
        public EventPagingArg(int pageIndex)
        {
            PageIndex = pageIndex;
        }
    }
    
    public class UCPagerViewModel : NotificationObject
    {
        #region 构造器
    
        public UCPagerViewModel()
        {
            NextPageCommand = new DelegateCommand(new Action(NextPageCommandExecute));
            PreviousPageCommand = new DelegateCommand(new Action(PreviousPageCommandExecute));
            HomePageCommand = new DelegateCommand(new Action(HomePageCommandExecute));
            TailPageCommand = new DelegateCommand(new Action(TailPageCommandExecute));
        }
    
            
        #endregion
    
        #region Property
        private int pageIndex;
    
        public int PageIndex
        {
            get { return pageIndex; }
            set 
            { 
                pageIndex = value;
                this.RaisePropertyChanged("PageIndex");
                if (PagingHandler != null)
                    PagingHandler.Invoke(new EventPagingArg(PageIndex));
            }
        }
    
        private int pageSize;
    
        public int PageSize
        {
            get { return pageSize; }
            set { pageSize = value; this.RaisePropertyChanged("PageSize"); }
        }
    
        private int pageCount;
    
        public int PageCount
        {
            get { return pageCount; }
            set { pageCount = value; this.RaisePropertyChanged("PageCount"); }
        }
    
        private int recordCount;
    
        public int RecordCount
        {
            get { return recordCount; }
            set { recordCount = value; this.RaisePropertyChanged("RecordCount"); }
        }
    
        private List<int> indexList;
    
        public List<int> IndexList
        {
            get { return indexList; }
            set { indexList = value; this.RaisePropertyChanged("IndexList"); }
        }
    
        #endregion
    
        #region 命令
    
        public DelegateCommand NextPageCommand { get; set; }
    
        public DelegateCommand PreviousPageCommand { get; set; }
    
        public DelegateCommand HomePageCommand { get; set; }
    
        public DelegateCommand TailPageCommand { get; set; }
    
        private void NextPageCommandExecute()
        {
            if(PageIndex<PageCount)
                PageIndex = PageIndex + 1;
        }
        private void PreviousPageCommandExecute()
        {
            if (PageIndex >1)
                PageIndex = PageIndex - 1;
        }
        private void HomePageCommandExecute()
        {
            PageIndex = 1;
        }
        private void TailPageCommandExecute()
        {
            PageIndex = PageCount;
        }
    
        #endregion
    
        #region 事件
    
        public EventPagingHandler PagingHandler { get; set; }
    
        #endregion
    }
    View Code

    UCPagerViewModel.CS包含三个部分,定义了一个委托、一个事件参数和ViewModel。使用该控件时先向其传入PageIndex、PageCount、RecordCount、PageSize和IndexList参数控制控件的现实,同时注册一个委托,当按下按钮或者选择页码时,分页控件会调用注册的委托,同时传递选择的页码。

    分页控件使用示例:

    <StackPanel>
        <DataGrid x:Name="emailDataGrid" ItemsSource="{Binding EmailList}" AutoGenerateColumns="False" VerticalGridLinesBrush="Red"
                    BorderBrush="DarkBlue" BorderThickness="1" LoadingRow="emailDataGrid_LoadingRow" CanUserAddRows="False" IsReadOnly="True">
            <DataGrid.Columns>
                <DataGridTextColumn Header="用户名" Width="100" Binding="{Binding UserName}"/>
                <DataGridTextColumn Header="密码" Width="*" Binding="{Binding Password}"/>
            </DataGrid.Columns>
        </DataGrid>
        <local:UCPager x:Name="mailPager"/>
    </StackPanel>

    后台代码:

    public partial class NetsMail : UserControl
    {
        public NetsMail()
        {
            InitializeComponent();
    
            UCPagerViewModel pagerViewModel = this.mailPager.UCPagerViewModel;
            NetsMailViewModel model = new NetsMailViewModel(pagerViewModel);
            this.DataContext = model;
        }
    
        private void emailDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
        {
            e.Row.Header = e.Row.GetIndex() + 1;
        }
    }

    在后台代码中,首先获取分页控件的ViewModel,然后将分页控件的ViewModel传入自己的ViewModel

    public NetsMailViewModel(UCPagerViewModel model)
    {
        pagerViewModel = model;
        pagerViewModel.PagingHandler += new EventPagingHandler(e=>PageIndex=e.PageIndex);
        NetsService = App.Container.GetExportedValue<INetsDesktopContract>();
    
        int recordCount;
        PageIndex = 1;
        emailList = NetsService.GetEmailAccounts(PageIndex, 20, out recordCount);
    
        pagerViewModel.PageIndex = PageIndex;
        pagerViewModel.PageSize = 20;
        pagerViewModel.RecordCount = recordCount;
        pagerViewModel.PageCount = recordCount % 20 > 0 ? recordCount / 20 + 1 : recordCount / 20;
    
        List<int> indexList = new List<int>();
        for (int i = 0; i < pagerViewModel.PageCount; i++)
        {
            indexList.Add(i + 1);
        }
        pagerViewModel.IndexList = indexList;
    }

    在ViewModel中获取用于显示的数据,同时向分页控件传入显示需要的数据。注意

    pagerViewModel.PagingHandler += new EventPagingHandler(e=>PageIndex=e.PageIndex);

    这句话,主要作用是注册一个委托,用于获取分页控件传递过来的PageIndex。

    
    
  • 相关阅读:
    多项同步请求,一起返回结果
    day.js 常用方法
    nest.js
    pdf.js react
    svg 贝塞尔
    idea修改项目中某个模块名称
    git安装和使用
    Cesium教程10把影像和天空改成背景图片
    Linux的挖矿木马病毒清除(kswapd0进程)
    Cesium的HeadingPitchRange 用法
  • 原文地址:https://www.cnblogs.com/Leman/p/3392636.html
Copyright © 2020-2023  润新知