WPF开发分页控件:实现可定制化分页功能及实现原理解析
概要
本文将详细介绍如何使用
WPF
(Windows Presentation Foundation)开发一个分页控件,并深入解析其实现原理。我们将通过使用XAML和C#代码相结合的方式构建分页控件,并确保它具有高度的可定制性,以便在不同的应用场景中满足各种需求。
一.简介
分页控件是在许多应用程序中常见的一种界面元素,特别是在数据展示的场景中。它允许用户浏览大量数据,并根据需要切换到
不同的
数据页。
二.需求分析
我们首先来分析一下一个分页控件的基本构成。
2.1 总条目数(TotalItems)
表示总数据量。
2.2 每页条目数(PageSize)
表示每页显示的条目数。
2.3 总页数(PageCount)
表示根据总条目数与每页条目数计算出来的页数。
2.4 分页/页码按钮数量(PageNumberCount)
分页控件中可以点击的页码按钮。
2.5 当前页(CurrentPage)
当前显示的页,通常高亮显示。
三.控件命令和事件
3.1 页面跳转命令(GoToPageCommand)
该命令用于在XAML代码中触发页面跳转操作。
3.2当前页变更事件
当CurrentPage参数改变后触发该事件,通常在该事件中执行数据查询操作。
四.代码实现
通过以上原理分析,我们提取出了分页控件需要包含的基本要素,下面我们通过这些信息来组装成一个分页控件。
1 <StyleTargetType="{x:Type local:Pager}"> 2 <SetterProperty="Template"> 3 <Setter.Value> 4 <ControlTemplateTargetType="{x:Type local:Pager}"> 5 <BorderBackground="{TemplateBinding Background}" 6 BorderBrush="{TemplateBinding BorderBrush}" 7 BorderThickness="{TemplateBinding BorderThickness}"> 8 <StackPanelOrientation="Horizontal"ClipToBounds="True"> 9 <ButtonCommand="{x:Static local:Pager.GoToPageCommand}"CommandParameter="1"Margin="0,0,5,0"Content="首页"></Button> 10 <ButtonCommand="{x:Static local:Pager.GoToPageCommand}"CommandParameter="-"Margin="5,0"Content="上一页"></Button> 11 <ItemsControlItemsSource="{TemplateBinding PageButtons}"> 12 <ItemsControl.ItemsPanel> 13 <ItemsPanelTemplate> 14 <StackPanelOrientation="Horizontal"/> 15 </ItemsPanelTemplate> 16 </ItemsControl.ItemsPanel> 17 <ItemsControl.ItemTemplate> 18 <DataTemplate> 19 <ToggleButtonMinWidth="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}" 20 Content="{Binding Page}" 21 IsChecked="{Binding IsCurrentPage}" 22 Command="{x:Static local:Pager.GoToPageCommand}" 23 CommandParameter="{Binding Page}" 24 Margin="5,0"/> 25 </DataTemplate> 26 </ItemsControl.ItemTemplate> 27 </ItemsControl> 28 <ButtonCommand="{x:Static local:Pager.GoToPageCommand}"CommandParameter="+"Margin="5,0"Content="下一页"></Button> 29 <ButtonCommand="{x:Static local:Pager.GoToPageCommand}"CommandParameter="尾页"Margin="5,0,0,0"Content="{DynamicResource LastPage}"></Button> 30 </StackPanel> 31 </Border> 32 </ControlTemplate> 33 </Setter.Value> 34 </Setter> 35 </Style>
五.多样化需求
在不同的业务场景下需要的分页控件可能不尽相同,那么如何来满足多样化需求呢,答案就是自定义控件模板。下面演示几种常见的分页控件如何实现。
只需要“上一页”、“下一页”的情况
1 <StyleTargetType="{x:Type Controls:Pager}"> 2 <SetterProperty="Template"> 3 <Setter.Value> 4 <ControlTemplateTargetType="{x:Type Controls:Pager}"> 5 <BorderBackground="{TemplateBinding Background}" 6 BorderBrush="{TemplateBinding BorderBrush}" 7 BorderThickness="{TemplateBinding BorderThickness}"> 8 <StackPanelOrientation="Horizontal"ClipToBounds="True"> 9 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="-"Margin="5,0"Content="{DynamicResource PreviousPage}"></Button> 10 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="+"Margin="5,0"Content="{DynamicResource NextPage}"></Button> 11 </StackPanel> 12 </Border> 13 </ControlTemplate> 14 </Setter.Value> 15 </Setter> 16 </Style>
只需要“首页”、“上一页”、“下一页”、“尾页”的情况。
1 <StyleTargetType="{x:Type Controls:Pager}"> 2 <SetterProperty="Template"> 3 <Setter.Value> 4 <ControlTemplateTargetType="{x:Type Controls:Pager}"> 5 <BorderBackground="{TemplateBinding Background}" 6 BorderBrush="{TemplateBinding BorderBrush}" 7 BorderThickness="{TemplateBinding BorderThickness}"> 8 <StackPanelOrientation="Horizontal"ClipToBounds="True"> 9 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="1"Margin="0,0,5,0"Content="{DynamicResource FirstPage}"></Button> 10 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="-"Margin="5,0"Content="{DynamicResource PreviousPage}"></Button> 11 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="+"Margin="5,0"Content="{DynamicResource NextPage}"></Button> 12 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="{TemplateBinding PageCount}"Margin="5,0,0,0"Content="{DynamicResource LastPage}"></Button> 13 </StackPanel> 14 </Border> 15 </ControlTemplate> 16 </Setter.Value> 17 </Setter> 18 </Style>
数字显示“首页”、“尾页”的情况。
1 <StyleTargetType="{x:Type Controls:Pager}"> 2 <SetterProperty="Template"> 3 <Setter.Value> 4 <ControlTemplateTargetType="{x:Type Controls:Pager}"> 5 <BorderBackground="{TemplateBinding Background}" 6 BorderBrush="{TemplateBinding BorderBrush}" 7 BorderThickness="{TemplateBinding BorderThickness}"> 8 <StackPanelOrientation="Horizontal"ClipToBounds="True"> 9 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}" 10 CommandParameter="1" 11 Content="1" 12 MinWidth="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}" 13 Margin="0,0,5,0"> 14 <Button.Visibility> 15 <MultiBindingConverter="{StaticResource PageNumberToVisibilityConverter}"ConverterParameter="First"> 16 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="CurrentPage"/> 17 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="PageNumberCount"/> 18 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="PageCount"/> 19 </MultiBinding> 20 </Button.Visibility> 21 </Button> 22 <ButtonIsEnabled="False"Margin="5,0"MinWidth="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}"Content="..."> 23 <Button.Visibility> 24 <MultiBindingConverter="{StaticResource PageNumberToVisibilityConverter}"ConverterParameter="First"> 25 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="CurrentPage"/> 26 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="PageNumberCount"/> 27 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="PageCount"/> 28 </MultiBinding> 29 </Button.Visibility> 30 </Button> 31 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="-"Margin="5,0"Content="{DynamicResource PreviousPage}"></Button> 32 <ItemsControlItemsSource="{TemplateBinding PageButtons}"> 33 <ItemsControl.ItemsPanel> 34 <ItemsPanelTemplate> 35 <StackPanelOrientation="Horizontal"/> 36 </ItemsPanelTemplate> 37 </ItemsControl.ItemsPanel> 38 <ItemsControl.ItemTemplate> 39 <DataTemplate> 40 <ToggleButtonMinWidth="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}" 41 Content="{Binding Page}" 42 Margin="5,0" 43 IsChecked="{Binding IsCurrentPage}" 44 Command="{x:Static Controls:Pager.GoToPageCommand}" 45 CommandParameter="{Binding Page}"/> 46 </DataTemplate> 47 </ItemsControl.ItemTemplate> 48 </ItemsControl> 49 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="+"Margin="5,0"Content="{DynamicResource NextPage}"></Button> 50 <ButtonIsEnabled="False"Margin="5,0"MinWidth="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}"Content="..."> 51 <Button.Visibility> 52 <MultiBindingConverter="{StaticResource PageNumberToVisibilityConverter}"> 53 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="CurrentPage"/> 54 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="PageNumberCount"/> 55 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="PageCount"/> 56 </MultiBinding> 57 </Button.Visibility> 58 </Button> 59 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}" 60 CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Controls:Pager},Path=PageCount}" 61 Content="{Binding RelativeSource={RelativeSource AncestorType=Controls:Pager},Path=PageCount}" 62 MinWidth="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}" 63 Margin="5,0,0,0"> 64 <Button.Visibility> 65 <MultiBindingConverter="{StaticResource PageNumberToVisibilityConverter}"> 66 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="CurrentPage"/> 67 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="PageNumberCount"/> 68 <BindingRelativeSource="{RelativeSource AncestorType=Controls:Pager}"Path="PageCount"/> 69 </MultiBinding> 70 </Button.Visibility> 71 </Button> 72 73 <StackPanelOrientation="Horizontal"Margin="5,0,0,0"> 74 <TextBlockText="转到"VerticalAlignment="Center"/> 75 <TextBoxx:Name="tbox_Page"Width="40"Margin="5,0"Padding="5"HorizontalContentAlignment="Center"VerticalAlignment="Center"/> 76 <TextBlockText="页"VerticalAlignment="Center"/> 77 <ButtonMargin="5,0,0,0"Command="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="{Binding ElementName=tbox_Page,Path=Text}">确定</Button> 78 </StackPanel> 79 </StackPanel> 80 </Border> 81 </ControlTemplate> 82 </Setter.Value> 83 </Setter> 84 </Style>
可以调整每页显示条目,可以显示总页数,可以跳转到指定页的情况。
1 <StyleTargetType="{x:Type Controls:Pager}"> 2 <SetterProperty="Template"> 3 <Setter.Value> 4 <ControlTemplateTargetType="{x:Type Controls:Pager}"> 5 <BorderBackground="{TemplateBinding Background}" 6 BorderBrush="{TemplateBinding BorderBrush}" 7 BorderThickness="{TemplateBinding BorderThickness}"> 8 <StackPanelOrientation="Horizontal"ClipToBounds="True"> 9 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="1"Margin="0,0,5,0"MinWidth="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}"Content="{DynamicResource FirstPage}"></Button> 10 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="-"Margin="5,0"MinWidth="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}"Content="{DynamicResource PreviousPage}"></Button> 11 <ItemsControlItemsSource="{TemplateBinding PageButtons}"> 12 <ItemsControl.ItemsPanel> 13 <ItemsPanelTemplate> 14 <StackPanelOrientation="Horizontal"/> 15 </ItemsPanelTemplate> 16 </ItemsControl.ItemsPanel> 17 <ItemsControl.ItemTemplate> 18 <DataTemplate> 19 <ToggleButtonMinWidth="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}" 20 Content="{Binding Page}" 21 Margin="5,0" 22 IsChecked="{Binding IsCurrentPage}" 23 Command="{x:Static Controls:Pager.GoToPageCommand}" 24 CommandParameter="{Binding Page}"/> 25 </DataTemplate> 26 </ItemsControl.ItemTemplate> 27 </ItemsControl> 28 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="+"Margin="5,0"MinWidth="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}"Content="{DynamicResource NextPage}"></Button> 29 <ButtonCommand="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="{TemplateBinding PageCount}"Margin="5,0,0,0"MinWidth="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}"Content="{DynamicResource LastPage}"></Button> 30 <StackPanelOrientation="Horizontal"Margin="5,0,0,0"> 31 <TextBlockMargin="0,0,5,0"Text="每页"VerticalAlignment="Center"/> 32 <ComboBoxMargin="5,0"SelectedIndex="0"VerticalContentAlignment="Center"SelectedItem="{Binding RelativeSource={RelativeSource AncestorType=Controls:Pager},Path=PageSize,Mode=OneWayToSource}"> 33 <sys:Int32>5</sys:Int32> 34 <sys:Int32>10</sys:Int32> 35 <sys:Int32>15</sys:Int32> 36 <sys:Int32>20</sys:Int32> 37 </ComboBox> 38 <TextBlockText="条"VerticalAlignment="Center"Margin="5,0"/> 39 <TextBlockVerticalAlignment="Center"Margin="5,0"> 40 <RunText="共"/> 41 <RunText="{Binding RelativeSource={RelativeSource AncestorType=Controls:Pager},Path=PageCount}"/> 42 <RunText="页"/> 43 </TextBlock> 44 <TextBlockText="转到"VerticalAlignment="Center"/> 45 <TextBoxx:Name="tbox_Page"Width="40"Margin="5,0"Padding="5"HorizontalContentAlignment="Center"VerticalAlignment="Center"/> 46 <TextBlockText="页"VerticalAlignment="Center"/> 47 <ButtonMargin="5,0,0,0"Command="{x:Static Controls:Pager.GoToPageCommand}"CommandParameter="{Binding ElementName=tbox_Page,Path=Text}">确定</Button> 48 </StackPanel> 49 </StackPanel> 50 </Border> 51 </ControlTemplate> 52 </Setter.Value> 53 </Setter> 54 </Style>
除了修改模板实现不同的形态的分页控件以外,还可以用图标替换掉“首页”、“上一页”、“下一页”、”尾页”等文字。
六.个性化控件外观
项目中的界面外观可能多种多样,有自己写的控件样式,也有使用第三方UI库的样式,如何跟它们搭配使用呢。
自定义控件样式
1 <StyleTargetType="Button"> 2 <SetterProperty="Padding"Value="5"/> 3 <SetterProperty="Background"Value="Red"/> 4 </Style> 5 <StyleTargetType="ToggleButton"> 6 <SetterProperty="Padding"Value="5"/> 7 <SetterProperty="Background"Value="Red"/> 8 </Style>
使用第三方UI库
1.HandyControl
1 <ResourceDictionary> 2 <ResourceDictionary.MergedDictionaries> 3 <ResourceDictionarySource="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml" /> 4 <ResourceDictionarySource="pack://application:,,,/HandyControl;component/Themes/Theme.xaml" /> 5 </ResourceDictionary.MergedDictionaries> 6 </ResourceDictionary>
2.MaterialDesign
1 <ResourceDictionary> 2 <ResourceDictionary.MergedDictionaries> 3 <materialDesign:CustomColorThemeBaseTheme="Light"PrimaryColor="#FF3561FF"SecondaryColor="#FF3561FF" /> 4 <ResourceDictionarySource="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" /> 5 </ResourceDictionary.MergedDictionaries> 6 </ResourceDictionary>