WPF管理系统自定义分页控件 - WPF特工队内部资料
最近做一个演示的管理系统项目,需要用到分页控件,在网上找了很多,依然找到与UI模版匹配的,最后干脆自己写一个。
分页控件分析:
1、分页控件分简单显示和复杂显示两种;
2、包含上一页、下一页以及页码明细逻辑处理;
3、页码总数小于7时显示默认显示,大于7时切换复杂显示;
4、页码数、索引、总条数计算等;
先来一张效果图:
啥也不说了直接上代码
MISPager.xaml部分
<ResourceDictionary 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:mis="clr-namespace:MIS.ClientUI.Controls" mc:Ignorable="d" > <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/MIS.ClientUI;component/Themes/Corlors.xaml" /> <ResourceDictionary Source="pack://application:,,,/MIS.ClientUI;component/Themes/Share.xaml" /> </ResourceDictionary.MergedDictionaries> <!--系统默认的分页控件--> <Style x:Key="MISDefaultDataPagerStyle" TargetType="{x:Type mis:MISPager}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type mis:MISPager}"> <Grid Margin="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <StackPanel Margin="0" Orientation="Horizontal"> <TextBlock TextWrapping="Wrap" Text="共" Margin="0" VerticalAlignment="Center"/> <TextBlock x:Name="PART_Count" HorizontalAlignment="Stretch" TextWrapping="Wrap" VerticalAlignment="Center" Text="1256" Foreground="#FF056DAE"/> <TextBlock TextWrapping="Wrap" Text="条记录,当前显示第" Margin="0" VerticalAlignment="Center"/> <TextBlock x:Name="PART_PageIndex" TextWrapping="Wrap" Text=" 2 " Margin="0" VerticalAlignment="Center" Foreground="#FF056DAE"/> <TextBlock TextWrapping="Wrap" Text="页" Margin="0" VerticalAlignment="Center"/> </StackPanel> <Border BorderBrush="Black" Grid.Column="1" Margin="0" HorizontalAlignment="Right"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="40"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="40"/> </Grid.ColumnDefinitions> <Border BorderBrush="#FFDDDDDD" BorderThickness="1,1,0,1" HorizontalAlignment="Stretch" Height="Auto" VerticalAlignment="Stretch" Width="Auto" CornerRadius="2,0,0,2"> <mis:MISImageButton BorderThickness="0" MISCornerRadius="0" GeometryIcon="{DynamicResource DefaultDataPagerPreviouspage}" Style="{DynamicResource DefaultISvgImageButtonStyle}" x:Name="PART_Previouspage" /> </Border> <Border Grid.ColumnSpan="1" HorizontalAlignment="Stretch" Height="Auto" VerticalAlignment="Stretch" Width="Auto" Grid.Column="1" BorderBrush="#FFDDDDDD" BorderThickness="0,1"> <StackPanel x:Name="PART_Content" Orientation="Horizontal"> </StackPanel> </Border> <Border BorderBrush="#FFDDDDDD" BorderThickness="1" Margin="0" Grid.Column="2" CornerRadius="0,2,2,0"> <mis:MISImageButton BorderThickness="0" MISCornerRadius="0" GeometryIcon="{DynamicResource DefaultDataPagerNextpage}" x:Name="PART_Nextpage" Style="{DynamicResource DefaultISvgImageButtonStyle}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0"/> </Border> </Grid> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
MISPager.cs部分
1 namespace MIS.ClientUI.Controls 2 { 3 /// <summary> 4 /// 分页控件 5 /// </summary> 6 [TemplatePart(Name = MISPager.MIS_PART_CONTENT, Type = typeof(StackPanel))] 7 [TemplatePart(Name = MISPager.MIS_PART_PREVIOUSPAGE, Type = typeof(MISImageButton))] 8 [TemplatePart(Name = MISPager.MIS_PART_NEXTPAGE, Type = typeof(MISImageButton))] 9 [TemplatePart(Name = MISPager.MIS_PART_COUNT, Type = typeof(TextBlock))] 10 [TemplatePart(Name = MISPager.MIS_PART_PAGEINDEX, Type = typeof(TextBlock))] 11 public partial class MISPager : Control 12 { 13 private const String MIS_PART_CONTENT = "PART_Content"; 14 private const String MIS_PART_PREVIOUSPAGE = "PART_Previouspage"; 15 private const String MIS_PART_NEXTPAGE = "PART_Nextpage"; 16 private const String MIS_PART_COUNT = "PART_Count"; 17 private const String MIS_PART_PAGEINDEX = "PART_PageIndex"; 18 19 private MISImageButton PART_Nextpage; //下一页事件 20 private MISImageButton PART_Previouspage; //上一页事件 21 private StackPanel PART_Content; //子页码 22 private TextBlock PART_Count; 23 private TextBlock PART_PageIndex; 24 25 private PagerType mPagerType = PagerType.Default; //当前分页控件类型,复杂、默认 26 private List<Int32> mCurrentPagers = new List<Int32>(); //当前分页控件显示的页码索引 27 private Boolean mCurrentIsAddEllipsisCtrl = false; //当前是否已添加省略号控件(当前还是可以直接在集合控件中比对) 28 29 public MISPager() 30 { 31 32 } 33 34 //初始化控件时调用的系统方法 35 public override void OnApplyTemplate() 36 { 37 base.OnApplyTemplate(); 38 this.PART_Content = this.GetTemplateChild(MISPager.MIS_PART_CONTENT) as StackPanel; 39 this.PART_Nextpage = this.GetTemplateChild(MISPager.MIS_PART_NEXTPAGE) as MISImageButton; 40 this.PART_Previouspage = this.GetTemplateChild(MISPager.MIS_PART_PREVIOUSPAGE) as MISImageButton; 41 this.PART_Count = this.GetTemplateChild(MISPager.MIS_PART_COUNT) as TextBlock; 42 this.PART_PageIndex = this.GetTemplateChild(MISPager.MIS_PART_PAGEINDEX) as TextBlock; 43 //计算页码数 44 this.PageCount = (Int32)Math.Ceiling((Double)this.Total / (Double)this.PageSize); 45 this.PART_Count.Text = this.Total.ToString(); 46 //当总页码小于7页,显示1、2、3、4、5、6、7 47 if (this.PageCount <= 7) 48 { 49 this.mPagerType = PagerType.Default; 50 for (int i = 0; i < this.PageCount; i++) 51 { 52 var misImgBtn = new MISLinkButton() 53 { 54 Content = (i + 1).ToString(), 55 Width = 35, 56 BorderThickness = new Thickness(1, 0, 0, 0), 57 Style = Application.Current.FindResource("DefaultLinkButton2Style") as Style 58 }; 59 this.mCurrentPagers.Add((i + 1)); 60 misImgBtn.Click += OnMisImgBtn_Click; 61 if (this.PART_Content != null) 62 { 63 this.PART_Content.Children.Add(misImgBtn); 64 } 65 } 66 } 67 else 68 { 69 this.mPagerType = PagerType.Complex; 70 for (int i = 0; i < 5; i++) 71 { 72 var misImgBtn = new MISLinkButton() { Content = (i + 1).ToString(), Width = 35, BorderThickness = new Thickness(1, 0, 0, 0), Style = Application.Current.FindResource("DefaultLinkButton2Style") as Style }; 73 misImgBtn.Click += OnMisImgBtn_Click; 74 if (i.Equals(0)) misImgBtn.Tag = 0; //设置左控制点 75 if (i.Equals(4)) misImgBtn.Tag = 5; //设置右控制点 76 this.mCurrentPagers.Add((i + 1)); 77 if (this.PART_Content != null) 78 { 79 this.PART_Content.Children.Add(misImgBtn); 80 } 81 } 82 this.PART_Content.Children.Add(new MISLinkButton() { Content = "...", Width = 35, BorderThickness = new Thickness(1, 0, 0, 0), Style = Application.Current.FindResource("DefaultLinkButton3Style") as Style }); 83 this.PART_Content.Children.Add(new MISLinkButton() { Content = this.PageCount.ToString(), Width = 35, BorderThickness = new Thickness(1, 0, 0, 0), Style = Application.Current.FindResource("DefaultLinkButton2Style") as Style }); 84 } 85 this.SetLinkButtonFocus(0); 86 this._SetNextpageAndPreviouspageState(); 87 if (this.PART_Previouspage != null) 88 { 89 this.PART_Previouspage.Click += OnPART_Previouspage_Click; 90 } 91 if (this.PART_Nextpage != null) 92 { 93 this.PART_Nextpage.Click += OnPART_Nextpage_Click; 94 } 95 } 96 97 #region 依赖属性 98 99 #region 当前DataGrid显示的数据总条数,用于计算页码数 100 /// <summary> 101 /// 当前DataGrid显示的数据总条数,用于计算页码数 102 /// </summary> 103 public Int32 Total 104 { 105 get { return (Int32)GetValue(TotalProperty); } 106 set { SetValue(TotalProperty, value); } 107 } 108 109 public static readonly DependencyProperty TotalProperty = 110 DependencyProperty.Register("Total", typeof(Int32), typeof(MISPager), new PropertyMetadata(0)); 111 112 #endregion 113 114 #region 当前DataGrid每页显示条数,用于计算页码数 115 /// <summary> 116 /// 每页显示条数 117 /// </summary> 118 public Int32 PageSize 119 { 120 get { return (Int32)GetValue(PageSizeProperty); } 121 set { SetValue(PageSizeProperty, value); } 122 } 123 124 public static readonly DependencyProperty PageSizeProperty = 125 DependencyProperty.Register("PageSize", typeof(Int32), typeof(MISPager), new PropertyMetadata(10)); 126 127 128 #endregion 129 130 #region 当前DataGrid当前页码索引 131 132 /// <summary> 133 /// 页码索引 134 /// </summary> 135 public Int32 PageIndex 136 { 137 get { return (Int32)GetValue(PageIndexProperty); } 138 set { SetValue(PageIndexProperty, value); } 139 } 140 141 public static readonly DependencyProperty PageIndexProperty = 142 DependencyProperty.Register("PageIndex", typeof(Int32), typeof(MISPager), new FrameworkPropertyMetadata(1)); 143 144 145 #endregion 146 147 #region 当前DataGrid总页数 148 /// <summary> 149 /// 页码数 150 /// </summary> 151 public Int32 PageCount 152 { 153 get { return (Int32)GetValue(PageCountProperty); } 154 set { SetValue(PageCountProperty, value); } 155 } 156 157 public static readonly DependencyProperty PageCountProperty = 158 DependencyProperty.Register("PageCount", typeof(Int32), typeof(MISPager), new PropertyMetadata(0)); 159 160 #endregion 161 162 #endregion 163 164 #region 路由事件 165 166 //注册分页路由事件 167 public static readonly RoutedEvent PageChangedEvent = EventManager.RegisterRoutedEvent("PageChanged", 168 RoutingStrategy.Bubble, typeof(EventHandler<PageChangedEventArgs>), typeof(MISPager)); 169 170 171 public event EventHandler<PageChangedEventArgs> PageChanged 172 { 173 add 174 { 175 this.AddHandler(PageChangedEvent, value); 176 } 177 remove 178 { 179 this.RemoveHandler(PageChangedEvent, value); 180 } 181 } 182 183 184 #endregion 185 186 #region 私有方法 187 188 /// <summary> 189 /// 计算当前选中的分页按钮的索引 190 /// </summary> 191 private Int32 CalculationCurrentSelectPagerButtonWithIndex() 192 { 193 //当前控件显示的页码集合 194 return this.mCurrentPagers.FindIndex((o) => { return o == this.PageIndex; }); 195 } 196 /// <summary> 197 /// 维护当前分页控件显示的页码数据 198 /// </summary> 199 /// <param name="addSubtract"></param> 200 private void _MaintainCurrentPagers(AddSubtract addSubtract) 201 { 202 if (addSubtract == AddSubtract.Add) 203 { 204 for (int i = 0; i < this.mCurrentPagers.Count; i++) 205 { 206 this.mCurrentPagers[i] = this.mCurrentPagers[i] + 1; 207 } 208 } 209 if (addSubtract == AddSubtract.subtract) 210 { 211 for (int i = 0; i < this.mCurrentPagers.Count; i++) 212 { 213 this.mCurrentPagers[i] = this.mCurrentPagers[i] - 1; 214 } 215 } 216 217 } 218 /// <summary> 219 /// 下一页 220 /// </summary> 221 private void OnPART_Nextpage_Click(object sender, RoutedEventArgs e) 222 { 223 var _index = this.CalculationCurrentSelectPagerButtonWithIndex() + 1; 224 this.PageIndex++; 225 this._SetNextpageAndPreviouspageState(); 226 if (this.mPagerType == PagerType.Complex) //复杂分页有效 227 { 228 // _index == 4 时为右侧控制点 229 if (_index == 4) 230 { 231 if (this.PageIndex == this.PageCount - 1) 232 { 233 this.PART_Nextpage.IsEnabled = false; //设置下一页不可用 234 } 235 //检测当前是否已添加省略号控件 236 if (!this.mCurrentIsAddEllipsisCtrl) 237 { 238 this.mCurrentIsAddEllipsisCtrl = true; 239 //在翻页控件第一个位置添加一个省略号控件 240 this.PART_Content.Children.Insert(0, new MISLinkButton() { Content = "...", Width = 35, BorderThickness = new Thickness(1, 0, 0, 0), Style = Application.Current.FindResource("DefaultLinkButton3Style") as Style }); 241 } 242 //刷新UI(所有的分页控件加1) 243 this._RefreshPager(AddSubtract.Add); 244 this._MaintainCurrentPagers(AddSubtract.Add); 245 } 246 else 247 { 248 this.SetLinkButtonFocus(_index); 249 } 250 } 251 else 252 { 253 //if (this.PageIndex == this.PageCount ) return; 254 this.SetLinkButtonFocus(_index); 255 } 256 257 } 258 /// <summary> 259 /// 上一页 260 /// </summary> 261 private void OnPART_Previouspage_Click(object sender, RoutedEventArgs e) 262 { 263 //当前PageIndex在界面上显示的索引,用于判断控制点 264 var _index = this.CalculationCurrentSelectPagerButtonWithIndex() - 1; 265 this.PageIndex--; 266 this._SetNextpageAndPreviouspageState(); 267 if (this.mPagerType == PagerType.Complex) //复杂分页有效 268 { 269 if (this.PageIndex == 1) 270 { 271 if (this.mCurrentIsAddEllipsisCtrl) 272 { 273 this.mCurrentIsAddEllipsisCtrl = false; 274 this.PART_Content.Children.RemoveAt(0); 275 this.SetLinkButtonFocus(0); 276 } 277 return; 278 } 279 if (_index == 0) //当前位置在左控制点时 280 { 281 //刷新UI(所有的分页控件减1) 282 this._RefreshPager(AddSubtract.subtract); 283 this._MaintainCurrentPagers(AddSubtract.subtract); 284 } 285 else 286 { 287 this.SetLinkButtonFocus(_index); 288 } 289 } 290 else 291 { 292 //if (this.PageIndex == 1) return; 293 this.SetLinkButtonFocus(_index); 294 } 295 } 296 297 private void SetLinkButtonFocus(Int32 index) 298 { 299 if (this.mCurrentIsAddEllipsisCtrl) //包含省略号控件 300 { 301 this.PART_Content.Children[index + 1].Focus(); 302 } 303 else 304 { 305 this.PART_Content.Children[index].Focus(); 306 } 307 } 308 309 protected virtual void OnPageChanged() 310 { 311 var eventArgs = new PageChangedEventArgs(this.PageIndex) { RoutedEvent = PageChangedEvent, Source = this }; 312 this.RaiseEvent(eventArgs); 313 } 314 315 private void _RefreshPager(AddSubtract addSubtract) 316 { 317 /* 318 * 1、默认分页的按钮为7个 319 * 2、当分页总数小于等于7时,直接显示1-7个分页按钮 320 * 3、当分页总数大于7时,显示当时为1、2、3、4、5、...、999(999为总页数) 321 * 4、 322 * **/ 323 if (this.PART_Content.Children.Count > 0) 324 { 325 int _index = 0; // 326 int _contentCount = this.PART_Content.Children.Count; 327 if (this.mCurrentIsAddEllipsisCtrl) //当前包含前缀省略号控件 328 { 329 _index = 1; 330 _contentCount = _contentCount - 1; 331 } 332 for (int i = 0; i < _contentCount - 2; i++) 333 { 334 var misLinkBtn = this.PART_Content.Children[_index] as MISLinkButton; 335 if (misLinkBtn != null) 336 { 337 misLinkBtn.Content = addSubtract == AddSubtract.Add ? (Convert.ToInt32(misLinkBtn.Content) + 1).ToString() : (Convert.ToInt32(misLinkBtn.Content) - 1).ToString(); 338 } 339 _index++; 340 } 341 if (addSubtract == AddSubtract.Add) 342 { 343 //设置倒数第一个按钮会选中状态 344 this.PART_Content.Children[_index - 2].Focus(); 345 } 346 else 347 { //设置第二个按钮会选中状态 348 if (this.mCurrentIsAddEllipsisCtrl) 349 { 350 this.PART_Content.Children[2].Focus(); 351 } 352 else 353 { 354 this.PART_Content.Children[1].Focus(); 355 } 356 } 357 } 358 359 360 361 362 363 364 365 } 366 367 /// <summary> 368 /// 设置上一页下一页按钮显示状态 369 /// </summary> 370 private void _SetNextpageAndPreviouspageState() 371 { 372 if (this.PageIndex == 1) 373 { 374 this.PART_Previouspage.IsEnabled = false; 375 } 376 if (this.PageIndex > 1) 377 { 378 this.PART_Previouspage.IsEnabled = true; 379 this.PART_Nextpage.IsEnabled = true; 380 } 381 if (this.mPagerType == PagerType.Complex) 382 { 383 if (this.PageIndex == this.PageCount - 1) 384 { 385 this.PART_Previouspage.IsEnabled = true; 386 this.PART_Nextpage.IsEnabled = false; 387 } 388 } 389 else 390 { 391 if (this.PageIndex == this.PageCount) 392 { 393 this.PART_Previouspage.IsEnabled = true; 394 this.PART_Nextpage.IsEnabled = false; 395 } 396 } 397 this.PART_PageIndex.Text = this.PageIndex.ToString(); 398 } 399 /// <summary> 400 /// 页码索引点击事件 401 /// </summary> 402 /// <param name="sender"></param> 403 /// <param name="e"></param> 404 private void OnMisImgBtn_Click(object sender, RoutedEventArgs e) 405 { 406 //获取当前点击的PageIndex 407 var misImgBtn = sender as MISLinkButton; 408 this.PageIndex = Convert.ToInt32(misImgBtn.Content); 409 this._SetNextpageAndPreviouspageState(); 410 //当为复杂控件时处理 411 if (this.mPagerType == PagerType.Complex) 412 { 413 this._RefreshPager(misImgBtn); 414 } 415 //执行路由回调 416 OnPageChanged(); 417 } 418 419 private void _RefreshPager(MISLinkButton misImgBtn) 420 { 421 //对比点击的控件 422 if (misImgBtn.Tag != null) 423 { 424 if (misImgBtn.Tag.Equals(0)) 425 { 426 if (this.PageIndex > 1) 427 { 428 if (this.PageIndex == 2 && this.mCurrentIsAddEllipsisCtrl) //当前点击第二页时,显示第一个并移除左侧的省略号控件 429 { 430 this.mCurrentIsAddEllipsisCtrl = false; 431 this.PART_Content.Children.RemoveAt(0); 432 } 433 //刷新UI(所有的分页控件减1) 434 this._RefreshPager(AddSubtract.subtract); 435 this._MaintainCurrentPagers(AddSubtract.subtract); 436 } 437 } 438 if (misImgBtn.Tag.Equals(5)) 439 { 440 //检测当前是否已添加省略号控件 441 if (!this.mCurrentIsAddEllipsisCtrl) 442 { 443 this.mCurrentIsAddEllipsisCtrl = true; 444 //在翻页控件第一个位置添加一个省略号控件 445 this.PART_Content.Children.Insert(0, new MISLinkButton() { Content = "...", Width = 35, BorderThickness = new Thickness(1, 0, 0, 0), Style = Application.Current.FindResource("DefaultLinkButton3Style") as Style }); 446 } 447 //刷新UI(所有的分页控件加1) 448 this._RefreshPager(AddSubtract.Add); 449 this._MaintainCurrentPagers(AddSubtract.Add); 450 } 451 } 452 #endregion 453 } 454 } 455 456 /// <summary> 457 /// 分页事件参数 458 /// </summary> 459 public class PageChangedEventArgs : RoutedEventArgs 460 { 461 462 public int PageIndex 463 { 464 get; 465 set; 466 } 467 468 public PageChangedEventArgs(int pageIndex) 469 : base() 470 { 471 PageIndex = pageIndex; 472 } 473 } 474 475 /// <summary> 476 /// 分页控件类型 477 /// </summary> 478 public enum PagerType 479 { 480 /// <summary> 481 /// 默认 482 /// </summary> 483 Default, 484 /// <summary> 485 /// 复杂 486 /// </summary> 487 Complex 488 } 489 490 public enum AddSubtract 491 { 492 Add, subtract 493 } 494 }