news 2026/6/10 11:47:52

WPF基于MVVM实现自定义分页控件

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WPF基于MVVM实现自定义分页控件

本文主要用于介绍WPF基于MVVM实现自定义分页控件的代码实现。
主要功能: 自定义页码,当前页/总页数, 上一页,下一页,返回首页,返回最后一页, 利用FontAwesome作为FontFamily实现icon的功能。

本代码中的ViewModelBase的实现请参照另一篇文章:WPF MVVM ViewModelBase(造轮子实现类似MVVMLight的功能)

1. 创建PaginationControl

1.1 Color Brush
<SolidColorBrush x:Key="HighlightBrush" Color="#E84315" /> <SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
1.2 PaginationControl.xaml.cs

不用更改任何代码

1.3 PaginationControl.xaml
<UserControl x:Class="MES.UI.Views.CustomControls.PaginationControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:i="http://schemas.microsoft.com/xaml/behaviors" xmlns:local="clr-namespace:MES.UI.Views.CustomControls" mc:Ignorable="d" Height="45"> <UserControl.Resources> <Style x:Key="paginationTB" TargetType="{x:Type TextBlock}"> <Setter Property="FontSize" Value="20"/> <Setter Property="FontFamily" Value="pack://application:,,,/Resources/#FontAwesome"/> <Setter Property="Margin" Value="5,15,5,10"/> <Setter Property="Foreground" Value="{StaticResource HighlightBrush}"/> <Setter Property="Cursor" Value="Hand"/> <Style.Triggers> <Trigger Property="IsEnabled" Value="True"> <Setter Property="Foreground" Value="{StaticResource HighlightBrush}"/> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/> </Trigger> </Style.Triggers> </Style> </UserControl.Resources> <StackPanel Orientation="Horizontal" VerticalAlignment="Center"> <TextBlock Text="Page Size:" Margin="5,15,5,10"></TextBlock> <ComboBox x:Name="PageSizeComboBox" ItemsSource="{Binding PageSizes}" SelectedItem="{Binding PageSize}" Width="70" VerticalAlignment="Center" HorizontalAlignment="Center"/> <TextBlock Style="{StaticResource paginationTB}" IsEnabled="{Binding EnabledPreviousButton}" Text="&#xf100;" x:Name="btnFirstPage" ToolTip="First Page"> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <i:InvokeCommandAction Command="{Binding FirstPageCommand}"/> </i:EventTrigger> </i:Interaction.Triggers> </TextBlock> <TextBlock Style="{StaticResource paginationTB}" IsEnabled="{Binding EnabledPreviousButton}" Text="&#xf104;" x:Name="btnPrevious" ToolTip="Previouse"> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <i:InvokeCommandAction Command="{Binding PreviousPageCommand}"/> </i:EventTrigger> </i:Interaction.Triggers> </TextBlock> <TextBlock Name="txtCurrentPageTextBlock" Text="{Binding CurrentPageText}" Margin="5,15,5,10" VerticalAlignment="Center" /> <TextBlock Style="{StaticResource paginationTB}" IsEnabled="{Binding EnabledNextButton}" Text="&#xf105;" x:Name="btnNext" ToolTip="Next" > <i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <i:InvokeCommandAction Command="{Binding NextPageCommand}"/> </i:EventTrigger> </i:Interaction.Triggers> </TextBlock> <TextBlock Style="{StaticResource paginationTB}" IsEnabled="{Binding EnabledNextButton}" Text="&#xf101;" x:Name="btnLastPage" ToolTip="Last Page" > <i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <i:InvokeCommandAction Command="{Binding LastPageCommand}"/> </i:EventTrigger> </i:Interaction.Triggers> </TextBlock> </StackPanel> </UserControl>

2. 创建PaginationControlViewModel

/// <summary>/// Pagination Control ViewModel/// </summary>publicclassPaginationControlViewModel:ViewModelBase{#regionPagination paramtersprivateint_currentPage;privateint_totalItems;privateint_pageSize=1;publicintTotalItems{get=>_totalItems;set{_totalItems=value;OnPropertyChanged(nameof(TotalItems));OnPropertyChanged(nameof(TotalPages));OnPropertyChanged(nameof(CurrentPageText));SetButtonStatus();}}publicintPageSize{get=>_pageSize;set{_pageSize=value;OnPropertyChanged(nameof(PageSize));OnPageChanged();}}publicintCurrentPage{get=>_currentPage;set{if(_currentPage!=value){_currentPage=value;OnPropertyChanged(nameof(CurrentPage));OnPageChanged();}}}publicstringCurrentPageText{get{return$"Page{CurrentPage}of{TotalPages}";}}publicintTotalPages=>(TotalItems+PageSize-1)/PageSize;privateObservableCollection<int>_pageSizes;publicObservableCollection<int>PageSizes{get{return_pageSizes;}set{_pageSizes=value;OnPropertyChanged(nameof(PageSizes));}}privatebool_enabledPreviousButton;publicboolEnabledPreviousButton{get{return_enabledPreviousButton;}set{_enabledPreviousButton=value;OnPropertyChanged(nameof(EnabledPreviousButton));}}privatebool_enabledNextButton;publicboolEnabledNextButton{get{return_enabledNextButton;}set{_enabledNextButton=value;OnPropertyChanged(nameof(EnabledNextButton));}}#endregionpublicICommandFirstPageCommand{get;}publicICommandPreviousPageCommand{get;}publicICommandNextPageCommand{get;}publicICommandLastPageCommand{get;}publiceventEventHandlerPageChanged;privateboolisInitialized=false;// avoid call OnPageChanged in initialpublicPaginationControlViewModel(){_pageSizes=newObservableCollection<int>{1,20,50,100,200,300,500};CurrentPage=1;// Initialize to the first pagePageSize=AgencyCRMConstants.DefaultPageSize;FirstPageCommand=newRelayCommand(_=>CurrentPage=1);PreviousPageCommand=newRelayCommand(_=>{if(CurrentPage>1)CurrentPage--;});NextPageCommand=newRelayCommand(_=>{if(CurrentPage<TotalPages)CurrentPage++;});LastPageCommand=newRelayCommand(_=>CurrentPage=TotalPages);isInitialized=true;}protectedvirtualvoidOnPageChanged(){if(isInitialized){PageChanged?.Invoke(this,EventArgs.Empty);}}privatevoidSetButtonStatus(){if(isInitialized){if(CurrentPage>1){EnabledPreviousButton=true;}else{EnabledPreviousButton=false;}if(CurrentPage>=1&&CurrentPage<TotalPages){EnabledNextButton=true;}else{EnabledNextButton=false;}}else{EnabledNextButton=false;EnabledPreviousButton=false;}}}

3. 调用

3.1 在CompanyListViewModel中引用PaginationControlViewModel
publicclassCompanyListViewModel:ViewModelBase,IViewModelDispose{#regionAgency.CRM API UrlsprivateconststringGetByCompanyNameAsync="api/Company/GetByCompanyName?CompanyName={0}&pageNumber={1}&pageSize={2}";#endregion#regionModelsprivatereadonlyIMESHttpClientService_mesHttpClientService;privateBackgroundWorker_backgroundWorker;publicPaginationControlViewModelPaginationViewModel;privatestring?_CompanyName;publicstring?CompanyName{get{return_CompanyName;}set{_CompanyName=value;OnPropertyChanged(nameof(CompanyName));}}privatebool_isEnableExport;publicboolIsEnableExport{get{return_isEnableExport;}set{_isEnableExport=value;OnPropertyChanged(nameof(IsEnableExport));}}privateCompanyDto?_selectedCompany;publicCompanyDto?SelectedCompany{get{return_selectedCompany;}set{_selectedCompany=value;OnPropertyChanged(nameof(SelectedCompany));}}privateObservableCollection<CompanyDto>_CompanyList;publicObservableCollection<CompanyDto>CompanyList{get{return_CompanyList;}set{_CompanyList=value;OnPropertyChanged(nameof(CompanyList));}}privateintpageSize=MESConstants.DefaultPageSize;privateintcurrentPage=1;#endregion#regionctorpublicCompanyListViewModel(){_mesHttpClientService=NInjectBase.Kernel.Get<IMESHttpClientService>();_CompanyList=new();_backgroundWorker=newBackgroundWorker();_backgroundWorker.DoWork+=BackgroundWorker_DoWork;_backgroundWorker.RunWorkerCompleted+=BackgroundWorker_RunWorkerCompleted;InitialParameters();}privatevoidInitialParameters(){_CompanyName=string.Empty;PaginationViewModel=newPaginationControlViewModel();PaginationViewModel.PageSize=MESConstants.DefaultPageSize;_selectedCompany=new();PaginationInitial();}#endregion#regionICommandspublicICommand?RefreshRecordsCommand{get{returnnewDelegateCommand(()=>{RefreshRecords();});}}publicICommand?ResetFilterCommand{get{returnnewDelegateCommand(()=>{ResetFilterFunction();});}}#endregion#regionFunctionsprivatevoidResetFilterFunction(){InitialParameters();RefreshRecords();}publicvoidRefreshRecords(){AppEvents.Instance.StartProgressBar(this,newProgressBarDisplayEventArgs(AppConstants.ProgressBarMessages.Generic.LOADING));_backgroundWorker.RunWorkerAsync(newList<string>(){CompanyName,currentPage.ToString(),pageSize.ToString()});}privatevoidBackgroundWorker_RunWorkerCompleted(object?sender,RunWorkerCompletedEventArgse){if(e.Error==null){varresult=e.ResultasPagedResultDto<CompanyDto>;if(result!=null){int.TryParse(result.TotalCount.ToString(),outvartotalCount);PaginationViewModel.TotalItems=totalCount;CompanyList=result.Items;this.IsEnableExport=CompanyList?.Count>0;}else{this.IsEnableExport=false;}}AppEvents.Instance.StopProgressBar(this);}privatevoidBackgroundWorker_DoWork(object?sender,DoWorkEventArgse){try{varparameters=e.ArgumentasList<string>;if(parameters==null||parameters.Count!=3)return;usingvarhttpClient=_mesHttpClientService.GetHttpClient();stringurlWithParameters=string.Format(GetByCompanyNameAsync,parameters[0],parameters[1],parameters[2]);varresponse=httpClient.GetAsync(urlWithParameters).Result;if(response.IsSuccessStatusCode){varjson=response.Content.ReadAsStringAsync().Result;varresult=JsonConvert.DeserializeObject<PagedResultDto<CompanyDto>>(json);e.Result=result;}}catch(Exceptionex){Log.Error("Error loading CRM users",ex);}}publicvoidDisposeRecordsAndEvents(){CompanyList=new();_backgroundWorker.DoWork-=BackgroundWorker_DoWork;_backgroundWorker.RunWorkerCompleted-=BackgroundWorker_RunWorkerCompleted;_backgroundWorker.Dispose();PaginationDispose();}#endregion#regionPaginationprivatevoidPaginationInitial(){PaginationViewModel=new();PaginationViewModel.PageChanged+=PaginationControlViewModel_PageChanged;}privatevoidPaginationDispose(){PaginationViewModel.PageChanged-=PaginationControlViewModel_PageChanged;}privatevoidPaginationControlViewModel_PageChanged(object?sender,EventArgse){pageSize=PaginationViewModel.PageSize;currentPage=PaginationViewModel.CurrentPage;RefreshRecords();}#endregion}
3.2 CompanyList.xaml中添加PaginationControl
<CustomControls:PaginationControl x:Name="paginationControl"></CustomControls:PaginationControl>
3.3 CompanyList.xaml.cs中为PaginationControl指定DataContext
privatevoidUserControl_Loaded(objectsender,System.Windows.RoutedEventArgse){paginationControl.DataContext=ViewModel.PaginationViewModel;ViewModel.RefreshRecords();}

4. 最终实现效果

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/5 14:26:58

Windows系统文件X3DAudio1_7.dll丢失损坏 下载方法

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

作者头像 李华
网站建设 2026/6/9 21:00:43

基于java的SpringBoot/SSM+Vue+uniapp的面向旅游的美食管理系统的详细设计和实现(源码+lw+部署文档+讲解等)

文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言 &#x1f31e;博主介绍&#xff1a;✌全网粉丝15W,CSDN特邀作者、211毕业、高级全…

作者头像 李华
网站建设 2026/5/31 0:58:17

计算机Java毕设实战-基于javaweb+mysql的校园招聘平台招聘管理系统基于springboot的启梦校园招聘平台【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/1 0:45:48

论文重复率不合格?5个科学方法,轻松降到目标值

论文重复率超30%&#xff1f;5个降重技巧&#xff0c;一次降到合格线 嘿&#xff0c;大家好&#xff01;我是AI菌。今天咱们来聊聊一个让无数学生头疼的问题&#xff1a;论文重复率飙到30%以上怎么办&#xff1f;别慌&#xff0c;我这就分享5个实用降重技巧&#xff0c;帮你一次…

作者头像 李华
网站建设 2026/6/7 9:55:28

2025最新!10个AI论文平台测评:继续教育写作难题全解决

2025最新&#xff01;10个AI论文平台测评&#xff1a;继续教育写作难题全解决 2025年AI论文平台测评&#xff1a;精准解决继续教育写作难题 在继续教育领域&#xff0c;撰写高质量论文已成为许多学员和从业者的必修课。然而&#xff0c;面对时间紧张、资料查找困难、格式不规范…

作者头像 李华
网站建设 2026/6/10 10:05:04

RestCloud ETL 4.0 Docker 部署指南

RestCloud ETL 4.0 Docker 部署指南 现状 截至当前日期官网的4.0的windows全能包无法正常下载&#xff0c;点击无反应。 采用Docker安装。 操作前准备 腾讯云账号注册windows专业版 或者 windows企业版已经可以访问的mongoDB服务 操作步骤 1. 启用 windows 自带的&#xff0c;h…

作者头像 李华