WPF+MVVM案例实战(六)- 自定义分页控件实现

在这里插入图片描述

文章目录

  • 1、项目准备
  • 2、功能实现
    • 1、分页控件 DataPager 实现
    • 2、分页控件数据模型与查询行为
    • 3、数据界面实现
  • 3、运行效果
  • 4、源代码获取


1、项目准备

打开项目 Wpf_Examples,新建 PageBarWindow.xaml 界面、PageBarViewModel.cs ,在用户控件库 UserControlLib中创建用户控件 DataPager.xaml 文件 。如下所示:
在这里插入图片描述
注意:如果没有 Wpf_Examples 项目,可以参考 WPF+MVVM案例实战(三)- 动态数字卡片效果实现,里面详细说明了整个项目的创建过程和环境包安装。

2、功能实现

1、分页控件 DataPager 实现

DataPager.xaml 页面代码实现如下:

<UserControl x:Class="UserControlLib.DataPager"
             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:local="clr-namespace:UserControlLib"
             x:Name="userControl"
         mc:Ignorable="d"
         Height="30"  HorizontalContentAlignment="Right" VerticalContentAlignment="Center">
    <Grid>
        <Grid.Resources>
            <Style x:Key="NormalTextBlockStyle" TargetType="{x:Type TextBlock}">
                <Setter Property="TextWrapping" Value="NoWrap" />
                <Setter Property="VerticalAlignment" Value="Center" />
                <Setter Property="FontSize" Value="14"></Setter>
                <Setter Property="Foreground" Value="#96bfd6" />
            </Style>
            <ControlTemplate x:Key="PageButtonTemplate" TargetType="{x:Type Button}">
                <TextBlock x:Name="textBlock" VerticalAlignment="Center" Text="{TemplateBinding Content}" HorizontalAlignment="Stretch" Cursor="Hand" Foreground="#96bfd6" />
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Foreground" TargetName="textBlock" Value="#FF554F4F" />
                        <Setter Property="Cursor" Value="None" />
                        <Setter Property="FontSize" Value="14"></Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>

            <Style x:Key="LabelStyle" TargetType="{x:Type Label}">
                <Setter Property="VerticalAlignment" Value="Center" />
                <Setter Property="FontSize" Value="14"></Setter>
                <Setter Property="Foreground" Value="#FFABA5A5" />
            </Style>
            <Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
                <Setter Property="HorizontalAlignment" Value="Center" />
                <Setter Property="HorizontalContentAlignment" Value="Center" />
                <Setter Property="VerticalAlignment" Value="Center" />
                <Setter Property="VerticalContentAlignment" Value="Center" />
                <Setter Property="Background" Value="#FFEAEBEC" />
                <Setter Property="FontSize" Value="14"></Setter>
                <Setter Property="Foreground" Value="#96bfd6" />
                <Setter Property="BorderBrush" Value="Transparent" />
                <Setter Property="BorderThickness" Value="0" />
                <Setter Property="CharacterCasing" Value="Upper" />
                <Setter Property="InputMethod.IsInputMethodEnabled" Value="False" />
            </Style>
        </Grid.Resources>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" x:Name="Stack_Main">
            <TextBlock Style="{DynamicResource NormalTextBlockStyle}" Text="共" />
            <TextBlock Text="{Binding TotalCount, ElementName=userControl}" Style="{DynamicResource NormalTextBlockStyle}" Margin="4,0" />
            <TextBlock Style="{DynamicResource NormalTextBlockStyle}" Text="行,每页" />
            <!--<TextBlock Text="{Binding PageSize, ElementName=userControl}" Style="{DynamicResource NormalTextBlockStyle}" Margin="4,0" />-->
            <ComboBox Grid.Column="0" Height="24" VerticalAlignment="Center" x:Name="cboxPageSize"  Padding="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
                  Width="60" Margin="5,0,0,0" SelectedItem="{Binding PageSize, ElementName=userControl,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Cursor="Hand" />
            <TextBlock Text="行,第" Style="{DynamicResource NormalTextBlockStyle}" />
            <TextBlock Text="{Binding PageIndex, ElementName=userControl}" Style="{DynamicResource NormalTextBlockStyle}" Margin="4,0,2,0" />
            <TextBlock Text="/" Style="{DynamicResource NormalTextBlockStyle}" />
            <TextBlock Text="{Binding PageCount, ElementName=userControl, Mode=OneWay}" Style="{DynamicResource NormalTextBlockStyle}" Margin="2,0,4,0" />
            <TextBlock Text="页" Style="{DynamicResource NormalTextBlockStyle}" />
            <Button x:Name="btnFirst" Content="首页" FontSize="14" Template="{DynamicResource PageButtonTemplate}" VerticalAlignment="Center" Margin="10,0,0,0" Click="btnFirst_Click" IsEnabled="{Binding CanGoFirstOrPrev, ElementName=userControl}" />
            <Button x:Name="btnPrev" Content="上一页" FontSize="14" Template="{DynamicResource PageButtonTemplate}" VerticalAlignment="Center" Margin="10,0,0,0" Click="btnPrev_Click" IsEnabled="{Binding CanGoFirstOrPrev, ElementName=userControl}" />
            <Button x:Name="btnNext" Content="下一页" FontSize="14" VerticalAlignment="Center" Template="{DynamicResource PageButtonTemplate}" Margin="10,0,10,0" Click="btnNext_Click" IsEnabled="{Binding CanGoLastOrNext, ElementName=userControl}" />
        </StackPanel>
    </Grid>
</UserControl>

DataPager.cs 后台代码实现如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace UserControlLib
{
    /// <summary>
    /// DataPager.xaml 的交互逻辑
    /// </summary>
    public partial class DataPager : UserControl, INotifyPropertyChanged
    {
        /// <summary>
        /// 分页前处理的事件,如果设置e.IsCancel=True将取消分页
        /// </summary>
        //public event PageChangingRouteEventHandler PageChanging;
        / <summary>
        / 分页后处理的事件
        / </summary>
        //public event PageChangedRouteEventHandler Closed;

        public static readonly RoutedEvent PageChangedEvent = EventManager.RegisterRoutedEvent("PageChangedEvent", RoutingStrategy.Bubble,
            typeof(EventHandler<PageChangedEventArgs>), typeof(DataPager));

        public delegate void PageChangedRouteEventHandler(object sender, PageChangedEventArgs e);

        public event RoutedEventHandler PageChanged
        {
            add { this.AddHandler(PageChangedEvent, value); }
            remove { this.RemoveHandler(PageChangedEvent, value); }
        }

        //public event Action Closed;

        public DataPager()
        {
            InitializeComponent();
            BindComBox();
        }

        #region 依赖属性--------------------------------------

        /// <summary>
        /// 当前页
        /// </summary>
        public int PageIndex
        {
            get { return (int)GetValue(PageIndexProperty); }
            set { SetValue(PageIndexProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CurrentPage.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PageIndexProperty =
            DependencyProperty.Register("PageIndex", typeof(int), typeof(DataPager), new UIPropertyMetadata(1, (sender, e) =>
            {
                var dp = sender as DataPager;
                dp.ChangeNavigationButtonState();
            }));

        /// <summary>
        /// 每页显示数据大小
        /// </summary>
        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(20, (sender, e) =>
            {
                var dp = sender as DataPager;
                if (dp == null) return;
                dp.InitData();
                dp.OnPageChanging(1);
                dp.ChangeNavigationButtonState();
            }));

        /// <summary>
        /// 记录数量
        /// </summary>
        public int TotalCount
        {
            get { return (int)GetValue(TotalCountProperty); }
            set
            {
                SetValue(TotalCountProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for TotalCount.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TotalCountProperty =
            DependencyProperty.Register("TotalCount", typeof(int), typeof(DataPager), new UIPropertyMetadata(0, (sender, e) =>
            {
                var dp = sender as DataPager;
                if (dp == null) return;
                dp.InitData();
                dp.ChangeNavigationButtonState();
            }));

        /// <summary>
        /// 总页数
        /// </summary>
        public int PageCount
        {
            get { return (int)GetValue(PageCountProperty); }
            private set { SetValue(PageCountProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PageCount.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PageCountProperty =
            DependencyProperty.Register("PageCount", typeof(int), typeof(DataPager), new UIPropertyMetadata(1));

        /// <summary>
        /// 是否可以点击首页和上一页按钮
        /// </summary>
        public bool CanGoFirstOrPrev
        {
            get
            {
                if (PageIndex <= 1) return false;
                return true;
            }
        }
        /// <summary>
        /// 是否可以点击最后页和下一页按钮
        /// </summary>
        public bool CanGoLastOrNext
        {
            get
            {
                if (PageIndex >= PageCount) return false;
                return true;
            }
        }

        #endregion 依赖属性--------------------------------------

        #region 下拉列表数据绑定-------------------------

        public void BindComBox()
        {
            List<string> pageSizeList = new List<string> { "20", "50", "100" };
            cboxPageSize.ItemsSource = pageSizeList;
            cboxPageSize.SelectedIndex = 0;
        }

        #endregion 下拉列表数据绑定-------------------------

        /// <summary>
        /// 初始化数据
        /// </summary>
        void InitData()
        {
            if (this.TotalCount == 0)
            {
                this.PageCount = 1;
            }
            else
            {
                this.PageCount = this.TotalCount % this.PageSize > 0 ? (this.TotalCount / this.PageSize) + 1 : this.TotalCount / this.PageSize;
            }
            if (this.PageIndex < 1)
            {
                this.PageIndex = 1;
            }
            if (this.PageIndex > this.PageCount)
            {
                this.PageIndex = this.PageCount;
            }
            if (this.PageSize < 1)
            {
                this.PageSize = 20;
            }
        }
        /// <summary>
        /// 点击首页按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnFirst_Click(object sender, RoutedEventArgs e)
        {
            OnPageChanging(1);
        }
        /// <summary>
        /// 点击上一页按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnPrev_Click(object sender, RoutedEventArgs e)
        {
            OnPageChanging(this.PageIndex - 1);
        }
        /// <summary>
        /// 点击下一页按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnNext_Click(object sender, RoutedEventArgs e)
        {
            OnPageChanging(this.PageIndex + 1);
        }
        /// <summary>
        /// 点击末页按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLast_Click(object sender, RoutedEventArgs e)
        {
            OnPageChanging(this.PageCount);
        }
        /// <summary>
        /// 点击跳转按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnGoTo_Click(object sender, RoutedEventArgs e)
        {
            int pageIndex = 1;
            try
            {
                //pageIndex = Convert.ToInt32(txtPageIndex.Text);
            }
            catch
            {
            }
            finally
            {
                OnPageChanging(pageIndex);
            }
        }
        /// <summary>
        /// 页码更改
        /// </summary>
        /// <param name="pageIndex"></param>
        internal void OnPageChanging(int pageIndex)
        {
            if (pageIndex < 1) pageIndex = 1;
            if (pageIndex > this.PageCount) pageIndex = this.PageCount;

            var newPageIndex = pageIndex;
            //var eventArgs = new PageChangingEventArgs() { OldPageIndex = oldPageIndex, NewPageIndex = newPageIndex };
            var eventArgs = new PageChangedEventArgs(PageChangedEvent, this);
            this.PageIndex = newPageIndex;
            RaiseEvent(eventArgs);
            //if (this.Closed != null)
            //{
            //    this.Closed();
            //}
            //if (!eventArgs.IsCancel)
            //{
            //    if (this.Closed != null)
            //    {
            //        this.Closed.Invoke();
            //    }
            //}
        }

        /// <summary>
        /// 通知导航按钮(首页,上一页,下一页,末页)状态的更改
        /// </summary>
        void ChangeNavigationButtonState()
        {
            this.NotifyPropertyChanged("CanGoFirstOrPrev");
            this.NotifyPropertyChanged("CanGoLastOrNext");
        }

        #region INotifyPropertyChanged成员

        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion INotifyPropertyChanged成员

        private void cboxPageSize_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            this.PageSize = ((System.Collections.Generic.KeyValuePair<int, string>)(cboxPageSize.SelectedItem)).Key;

            var param = new PageChangedEventArgs(PageChangedEvent, this);

            RaiseEvent(param);

            //if (Closed != null)
            //{
            //    this.Closed.Invoke();
            //}
        }

        private void TxtPageIndex_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            Regex re = new Regex("[^0-9]+");
            e.Handled = re.IsMatch(e.Text);
        }
    }

    public class PageChangedEventArgs : RoutedEventArgs
    {
        public PageChangedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { }
        public DataPager dataPager { get; set; }
    }
}


2、分页控件数据模型与查询行为

在这里插入图片描述PageBarAction.cs 代码实现如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UserControlLib.Models;

namespace UserControlLib.Actions
{
    public class PageBarAction
    {
        public static bool GetDataByPage<T>(int pageSize, int pageIndex, List<T> list, T obj) where T : DataModel
        {
            var temp = list.FirstOrDefault(t => t.Key == obj.Key);
            if (temp == null) return false;
            int index = list.IndexOf(temp);
            if (index >= pageSize * (pageIndex - 1) && index < pageSize * pageIndex)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

DataModel.cs 数据模型如下:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;

namespace UserControlLib.Models
{
    [Serializable]
    public class DataModel : ObservableObject
    {
        private string key = Guid.NewGuid().ToString();
        /// <summary>
        /// Key
        /// </summary>
        public string Key
        {
            get => key;
            set => SetProperty(ref key, value);
        }

        private int order = 0;
        /// <summary>
        /// 序号
        /// </summary>
        public int Order
        {
            get => order;
            set => SetProperty(ref order, value);
        }

        private bool isSelected = false;
        /// <summary>
        /// 是否选中
        /// </summary>
        public bool IsSelected
        {
            get => isSelected;
            set => SetProperty(ref isSelected, value);
        }

        private bool changedEnabled = false;
        /// <summary>
        /// 修改使能
        /// </summary>
        public bool ChangedEnabled
        {
            get => changedEnabled;
            set => SetProperty(ref changedEnabled, value);
        }

        private List<string> errors = new List<string>();
        /// <summary>
        /// 错误提示集合
        /// </summary>
        public List<string> Errors
        {
            get { return errors; }
            set { errors = value; }
        }


        private string error = string.Empty;
        /// <summary>
        /// 错误提示,未使用
        /// </summary>
        public string Error
        {
            get { return error; }
            set { error = value; }
        }

        public string this[string columnName]
        {
            get
            {
                var vc = new ValidationContext(this, null, null);
                vc.MemberName = columnName;
                var res = new List<System.ComponentModel.DataAnnotations.ValidationResult>();
                var result = this.GetType().GetProperty(columnName).GetValue(this, null);
                if (res.Count > 0)
                {
                    return string.Join(Environment.NewLine, res.Select(r => r.ErrorMessage).ToArray());
                }
                return string.Empty;
            }
        }

        public string GetHashKey()
        {
            return Guid.NewGuid().GetHashCode().ToString();
        }
    }

}

自定义控件样式如下
在这里插入图片描述

3、数据界面实现

这里我们使用 DataGrid 显示数据,用 DataPager 分页控件实现分页控制。

PageBarWindow.xaml 界面代码如下:

<Window x:Class="Wpf_Examples.Views.PageBarWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Wpf_Examples.Views"
        xmlns:uc="clr-namespace:UserControlLib;assembly=UserControlLib"
        DataContext="{Binding Source={StaticResource Locator},Path=PageBar}"
        mc:Ignorable="d"
        Title="PageBarWindow" Height="450" Width="800">
    <Window.Resources>
        <!--DataGrid样式-->
        <Style TargetType="DataGrid" >
            <!--网格线颜色-->
            <Setter Property="IsReadOnly" Value="True" />
            <Setter Property="FontSize" Value="16" />
            <Setter Property="CanUserResizeColumns" Value="False"/>
            <Setter Property="CanUserResizeRows" Value="False"/>
            <Setter Property="AutoGenerateColumns" Value="False" />
            <Setter Property="CanUserAddRows" Value="False" />
            <Setter Property="BorderBrush" Value="#FFF5F7F5" />
        </Style>

        <!--标题栏样式-->
        <Style TargetType="DataGridColumnHeader" >
            <Setter Property="SnapsToDevicePixels" Value="True" />
            <Setter Property="MinWidth" Value="0" />
            <Setter Property="MinHeight" Value="28" />
            <Setter Property="FontSize" Value="16" />
            <Setter Property="Cursor" Value="Hand" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="DataGridColumnHeader">
                        <Border x:Name="BackgroundBorder" BorderThickness="0,1,0,1" Width="Auto">
                            <Grid >
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>
                                <ContentPresenter  Margin="0,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                                <Path x:Name="SortArrow" Visibility="Collapsed" Data="M0,0 L1,0 0.5,1 z" Stretch="Fill"  Grid.Column="2" Width="8" Height="6" Fill="White" Margin="0,0,50,0" 
                     VerticalAlignment="Center" RenderTransformOrigin="1,1" />
                                <Rectangle Width="1" Fill="#d6c79b" HorizontalAlignment="Right" Grid.ColumnSpan="1" />
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="Height" Value="25"/>
        </Style>
        <!--行样式触发-->
        <!--背景色改变必须先设置cellStyle 因为cellStyle会覆盖rowStyle样式-->
        <Style  TargetType="DataGridRow">
            <Setter Property="Background" Value="#F2F2F2" />
            <Setter Property="Height" Value="25"/>
            <Setter Property="Foreground" Value="Black" />
            <Style.Triggers>
                <!--隔行换色-->
                <Trigger Property="AlternationIndex" Value="0" >
                    <Setter Property="Background" Value="#e7e7e7" />
                </Trigger>
                <Trigger Property="AlternationIndex" Value="1" >
                    <Setter Property="Background" Value="#f2f2f2" />
                </Trigger>

                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="LightGray"/>
                    <!--<Setter Property="Foreground" Value="White"/>-->
                </Trigger>

                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Foreground" Value="Black"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <!--单元格样式触发-->
        <Style TargetType="DataGridCell">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="DataGridCell">
                        <TextBlock TextAlignment="Center" VerticalAlignment="Center"  >
                    <ContentPresenter />
                        </TextBlock>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Foreground" Value="Black"/>
                </Trigger>
            </Style.Triggers>
        </Style>

        <Style TargetType="DataGrid" x:Key="DataGridStyle1">
            <!--  网格线颜色  -->
            <Setter Property="RowHeaderWidth" Value="0" />
            <Setter Property="BorderThickness" Value="{StaticResource DataGrid.BorderThickness}" />
            <Setter Property="HeadersVisibility" Value="Column" />
            <Setter Property="Background" Value="{StaticResource ColumnHeader.Background}" />
            <Setter Property="BorderBrush" Value="{StaticResource DataGrid.BorderBrush}" />
            <Setter Property="HorizontalGridLinesBrush" Value="#00E9ECF1" />
            <Setter Property="VerticalGridLinesBrush" Value="#00E9ECF1" />
            <Setter Property="UseLayoutRounding" Value="True" />
            <Setter Property="SnapsToDevicePixels" Value="True" />
            <Setter Property="AutoGenerateColumns" Value="False" />
            <Setter Property="CanUserAddRows" Value="False" />
            <Setter Property="CanUserReorderColumns" Value="False" />
            <Setter Property="CanUserResizeColumns" Value="False" />
            <Setter Property="CanUserResizeRows" Value="False" />
            <Setter Property="CanUserSortColumns" Value="False" />
            <Setter Property="GridLinesVisibility" Value="None" />
            <Setter Property="IsReadOnly" Value="True" />
            <Setter Property="RowHeight" Value="{StaticResource DataGridRow.Height}" />
            <Setter Property="SelectionMode" Value="Single" />
        </Style>
    </Window.Resources>
    <Grid>
        <!--当前托盘采集数据列表分页显示面板-->
        <Border Grid.Row="3" BorderThickness="1"
BorderBrush="Gray"
CornerRadius="5" Margin="8"
Background="Transparent">
            <Grid Margin="5">
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="30"/>
                </Grid.RowDefinitions>
                <DataGrid Background="Transparent" HorizontalScrollBarVisibility="Disabled" 
    ItemsSource="{Binding ViewSource}" AutoGenerateColumns="false" Margin="2" Style="{StaticResource DataGridStyle1}">
                    <DataGrid.Columns>
                        <DataGridTextColumn Binding="{Binding Id}" Header="序号" Width="80"/>
                        <DataGridTextColumn Binding="{Binding Name}" Header="姓名" Width="100"/>
                        <DataGridTextColumn Binding="{Binding Gender}" Header="性别" Width="80"/>
                        <DataGridTextColumn Binding="{Binding Age}" Header="年龄" Width="80"/>
                        <DataGridTextColumn Binding="{Binding Email}" Header="邮箱" Width="*"/>
                        <DataGridTextColumn Binding="{Binding Phone}" Header="手机号" Width="*"/>
                    </DataGrid.Columns>
                </DataGrid>
                <uc:DataPager Grid.Row="1" HorizontalAlignment="Right"  PageIndex="{Binding PageIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
          PageSize="{Binding PageSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
          TotalCount="{Binding TotalCount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            </Grid>
        </Border>
    </Grid>
</Window>

本文把DataGrid 的属性参数提取出来放在全局配置中。如下所示:

 <Application.Resources>
     <ResourceDictionary>

     <!--界面边框-->
     <SolidColorBrush x:Key="Border.BorderBrush" Color="#50F150" />

     <sys:Double x:Key="DataGridRow.Height">33</sys:Double>
     <!--  表格外边框线粗细,一般不修改  -->
     <Thickness x:Key="DataGrid.BorderThickness" Bottom="1" Left="1" Right="1" Top="1"/>
     <!--  行边框粗细,一般不修改  -->
     <Thickness x:Key="DataGridRow.BorderThickness" Bottom="0" Left="0" Right="0" Top="1"/>
     <!--  表格外边框颜色  -->
     <SolidColorBrush x:Key="DataGrid.BorderBrush" Color="#E9ECF1" />
     <!--  列头背景色  -->
     <SolidColorBrush x:Key="ColumnHeader.Background" Color="#F6F7FB" />
     <!--  列头边框颜色  -->
     <SolidColorBrush x:Key="ColumnHeader.BorderBrush" Color="#E9ECF1" />

     <vm:ViewModelLocator xmlns:vm="clr-namespace:Wpf_Examples.ViewModels" x:Key="Locator"></vm:ViewModelLocator>
     </ResourceDictionary>
 </Application.Resources>

PageBarViewModel.cs 代码实现如下:

using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using Wpf_Examples.Models;

namespace Wpf_Examples.ViewModels
{
    public class PageBarViewModel:ObservableObject
    {
        #region 字段
        public ICollectionView ViewSource { set; get; }
        int showDataCount = 0;

        #endregion

        #region 属性
        /// <summary>
        /// 分页页序号
        /// </summary>
        private int pageIndex = 1;
        public int PageIndex
        {
            get { return pageIndex; }
            set { SetProperty(ref pageIndex, value); RefreshView(); }
        }
        /// <summary>
        /// 分页每页显示数据条数
        /// </summary>
        private int pageSize;
        public int PageSize
        {
            get { return pageSize; }
            set { SetProperty(ref pageSize, value); RefreshView(); }
        }
        /// <summary>
        /// 总显示数据条数
        /// </summary>
        private int totalCount = 0;
        public int TotalCount
        {
            get { return totalCount; }
            set { SetProperty(ref totalCount, value); }
        }
        /// <summary>
        /// 需要显示的数据集合
        /// </summary>
        private ObservableCollection<DataInfoListModel> dataInfoList = new ObservableCollection<DataInfoListModel>();
        public ObservableCollection<DataInfoListModel> DataInfoList
        {
            get { return dataInfoList; }
            set { SetProperty(ref dataInfoList, value); }
        }



        #endregion

        public PageBarViewModel()
        {
            Random random = new Random();
            for (int i = 0; i < 30; i++)
            {
                DataInfoListModel dataInfoListModel = new DataInfoListModel();
                dataInfoListModel.Order = (i + 1);
                dataInfoListModel.Id = (i + 1); 
                dataInfoListModel.Name = "测试"+(i+1)+"号";
                dataInfoListModel.Gender = "男";
                dataInfoListModel.Age = random.Next(10,80);
                dataInfoListModel.Phone = "17455861459";
                dataInfoListModel.Email = "1453849257@qq.com";
                DataInfoList.Add(dataInfoListModel);
            }
            TotalCount = DataInfoList.Count;
            ViewSource = CollectionViewSource.GetDefaultView(DataInfoList);
            ViewSource.Filter = new Predicate<object>(OnFilterMovie);
        }


        private void RefreshView()
        {
            showDataCount = 0;
            ViewSource.Refresh();
        }

        /// <summary>
        /// 数据过滤器
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private bool OnFilterMovie(object obj)
        {
            if (DataInfoList.Count == 0) return false;
            if (showDataCount >= pageSize) return false;
            if (!(obj is DataInfoListModel info)) return false;
            bool flag = UserControlLib.Actions.PageBarAction.GetDataByPage(pageSize, PageIndex, DataInfoList.ToList(), info);
            if (flag) showDataCount++;
            return flag;
        }

    }
}

3、运行效果

在这里插入图片描述

4、源代码获取

CSDN下载链接:WPF+MVVM案例实战(六)- 自定义分页控件实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/904705.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Docker】构建Linux云桌面环境

目录 一、说明 二、离线安装Docker 1&#xff09;将下载的包上传到服务器上去 2&#xff09;安装docker 3) 启动docker 4&#xff09;配置加速器 三、安装云桌面镜像 四、启动云桌面 方式一&#xff1a;docker命令直接运行 方式二&#xff1a;docker-compose方式 五…

Easysearch 与 LLM 融合打造知识库系统

文章目录 一、LangChain 简介二、RAG 产生的背景及其局限性三、RAG 工作流程四、 Easysearch 结合 LLM 实现 RAG&#xff08;1&#xff09;Easysearch 简介&#xff08;2&#xff09;结合实现RAG 五、 Easysearch 结合 LLM 实现 RAG 的优势&#xff08;1&#xff09;提高检索准…

驱动-----adc

在key1.c的基础上进行对adc1.c进行编写 首先将文件里面的key全部改为adc 再修改一下设备号 按键和adc的区别是什么,按键只需要按一下就触发了,并且不需要返回一个值出来, adc要初始化,启动,返回值 以下是裸机adc的代码: #include <s3c2440.h> #include "ad…

快速生成高质量提示词,Image to Prompt 更高效

抖知书老师推荐&#xff1a; 随着 AI 技术的不断发展&#xff0c;视觉信息与语言信息之间的转换变得越来越便捷。在如今的数字化生活中&#xff0c;图像与文字的交互需求愈发旺盛&#xff0c;很多人都希望能轻松将图像内容直接转化为文本描述。今天我们来推荐一款实用的 AI 工…

FileLink跨网文件传输与传统文件传输对比

在数字化时代&#xff0c;文件传输已成为企业日常运营不可或缺的一部分。然而&#xff0c;随着企业规模的扩大和业务的复杂化&#xff0c;传统的文件传输方式逐渐暴露出诸多不足。本文将对比FileLink跨网文件传输与传统文件传输方式&#xff0c;揭示FileLink在高效性、安全性和…

渗透测试-百日筑基—文件上传篇特征截断渲染%00绕过——下篇

目录 day10-渗透测试文件上传篇&绕过&特征&截断&渲染 一、黑名单大小写绕过代码分析 1、获取文件后缀名进行判断&#xff0c;如果后缀在这个字典里就禁止上传。 2、黑名单大小写绕过攻击 二、利用 windows 系统特征绕过上传 1、windows 系统特征绕过漏洞…

YoloV9改进策略:Block改进|RFE模块,提高小物体的识别精度|即插即用|代码+修改过程

摘要 论文介绍 本文介绍了一种基于YOLOv5的人脸检测方法,命名为YOLO-FaceV2。该方法旨在解决人脸检测中的尺度变化、简单与困难样本不平衡以及人脸遮挡等问题。通过引入一系列创新模块和损失函数,YOLO-FaceV2在WiderFace数据集上取得了优异的表现,特别是在小物体、遮挡和困…

CodeQL学习笔记(3)-QL语法(模块、变量、表达式、公式和注解)

最近在学习CodeQL&#xff0c;对于CodeQL就不介绍了&#xff0c;目前网上一搜一大把。本系列是学习CodeQL的个人学习笔记&#xff0c;根据个人知识库笔记修改整理而来的&#xff0c;分享出来共同学习。个人觉得QL的语法比较反人类&#xff0c;至少与目前主流的这些OOP语言相比&…

QT-使用QSS美化UI界面

一、QSS简介&#xff1a; Qt Style Sheet&#xff1a;Qt样式表&#xff0c;用来自定义控件外观的一种机制&#xff0c;可以把他类比成CSS&#xff08;CSS主要功能与最终目的都是能使界面的表现与界面的元素分离&#xff09;。QSS机制使应用程序也能像web界面那样随意地改变外观…

江协科技STM32学习- P23 DMA 直接存储器存取

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

Adb命令大全

本文列举了几乎所有的adb命令&#xff0c;方便Android学习者或者开发工程师在日常学习开发过程中查询使用。建议收藏。 Adb Server adb kill-server adb start-server 重启 adb reboot adb reboot recovery adb reboot-bootloader adb root //restarts adb with root permis…

信息安全保障人员CISAW认证有哪些级别和方向?

在信息安全领域&#xff0c;CISAW认证已经成为了一个重要的资格认证标准。 它不仅代表了专业技术水平的认可&#xff0c;也是进入该领域工作和发展的重要凭证。 对于有志于从事信息安全相关工作的人员来说&#xff0c;了解其报考条件是迈向成功的第一步。 CISAW认证体系涵盖…

微信小程序中点击搜素按钮没有反应,可能是样式问题(按钮被其他元素覆盖或遮挡)

文章目录 1. 确认 bindtap 绑定在正确的元素上2. 检查是否有遮挡或重叠元素3. 检查 this 上下文绑定问题4. 清除微信小程序开发者工具的缓存5. 用微信开发者工具查看事件绑定6. 确保 handleSearch 没有拼写错误进一步调试 1、searchResults.wxml2、searchResults.wxss3、search…

Git获取本地仓库和常用指令

一、获取本地仓库 1&#xff09;在电脑的任意位置创建一个空目录&#xff08;例如test01&#xff09;作为我们的本地Git仓库 2&#xff09;进入这个目录中&#xff0c;点击右键打开Git bash窗口 3&#xff09;执行命令git init&#xff08;初始化当前目录为一个git仓库&…

两个好用的GIF制作软件,轻松制作动图表情包

分享2个好用的GIF制作软件&#xff0c;支持GIF录制、视频转GIF、图片合成GIF&#xff0c;可以满足绝大部分的GIF制作需求&#xff01; 1、ScreenToGif&#xff1a;GIF录制/视频转GIF 一款特别好用的GIF录制和编辑工具&#xff0c;界面简单易用。安装后一打开就能看到它的四大…

RN安卓应用打包指南

React Native&#xff08;简称RN&#xff09;是一个用于开发跨平台移动应用的开源框架&#xff0c;它允许你使用JavaScript和React来构建在iOS和Android上运行的应用。要将React Native项目打包成安卓应用&#xff08;APK&#xff09;&#xff0c;可以按照以下步骤进行&#xf…

【生物学&水族馆】金鱼成体幼苗检测活体识别系统源码&数据集全套:改进yolo11-Parc

改进yolo11-DynamicHGNetV2等200全套创新点大全&#xff1a;金鱼成体幼苗检测活体识别系统源码&#xff06;数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.10.30 注意&#xff1a;由于项目一直在更新迭代&#xff0c;上面“1.图片效果展示”和“2.视频效果展示”展…

【商汤科技-注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

node和npm版本冲突

问题描述&#xff1a; 解决办法&#xff1a; 一、 查看自己当前的node和npm版本 node -v npm -v 二、 登录node官网地址 node官网地址 https://nodejs.org/zh-cn/about/previous-releases 查看与自己node版本兼容的是哪一版本的npm,相对应进行更新即可。 三 升级node 下载最…

python 爬虫 入门 五、抓取图片、视频

目录 一、图片、音频 二、下载视频&#xff1a; 一、图片、音频 抓取图片的手法在上一篇python 爬虫 入门 四、线程&#xff0c;进程&#xff0c;协程-CSDN博客里面其实有&#xff0c;就是文章中的图片部分&#xff0c;在那一篇文章&#xff0c;初始代码的28&#xff0c;29行…