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

news2024/11/25 12:20:00

在这里插入图片描述

文章目录

  • 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案例实战(六)- 自定义分页控件实现

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WASM 使用说明23事(RUST实现)

文章目录 1. wasm是什么1.1 chatgpt定义如下:1.2 wasm关键特性&#xff1a; 2. wasm demo2.1 cargo 创建项目2.2 编写code2.3 安装wasm-pack2.4 编译 3.1 html页面引用wasm代码&#xff08;js引用&#xff09;3.2 访问页面4 导入js function4.1 编写lib.rs文件&#xff0c;内容…

UML 总结(基于《标准建模语言UML教程》)

定义 UML 又称为统一建模语言或标准建模语言&#xff0c;是一种标准的图形化建模语言&#xff0c;它是面向对象分析与设计的一种标准表示。尽管UML 本身没有对过程有任何定义&#xff0c;但UML 对任何使用它的方法&#xff08;或过程&#xff09;提出的要求是&#xff1a;支持用…

【含开题报告+文档+PPT+源码】基于vue框架的东升餐饮点餐管理平台的设计与实现

开题报告 在当前信息化社会背景下&#xff0c;餐饮行业正经历着由传统线下服务模式向线上线下深度融合的转变。随着移动互联网技术及大数据应用的飞速发展&#xff0c;用户对于餐饮服务平台的需求也日益多元化和个性化。他们期望能在一个集便捷、高效、个性化于一体的平台上完…

自动化测试工具Ranorex Studio(十六)-添加新Action

在Action表中&#xff0c;有两种手动添加action的方式。 一种方法是指定Action本身&#xff08;’添加新Action’&#xff09;&#xff0c;然后分配对应的对象库条目&#xff08;在多数情况下&#xff09;。 第二种方法是直接把对象库条目拖放到Action表内&#xff0c;然后生成…

力扣 中等 2466.统计构造好字符串的方案数

文章目录 题目介绍题解 题目介绍 题解 题意&#xff1a;每次可以爬 zero 或 one 个台阶&#xff0c;返回爬 low 到 high 个台阶的方案数。 和上题337.组合总和 &#xff08;链接&#xff09;的思路一样&#xff0c;只不过是将可以爬的台阶数从数组换成了两个数&#xff08;ze…

视频美颜平台的搭建指南:基于直播美颜SDK的完整解决方案

众所周知&#xff0c;直播美颜SDK是实现视频美颜功能的核心。本文将详细解析如何基于直播美颜SDK搭建一个完整的视频美颜平台。 一、视频美颜SDK的核心功能 直播美颜SDK作为平台的技术核心&#xff0c;能够提供丰富的美颜效果和稳定的视频处理能力。通常&#xff0c;SDK具备以…

iOS AVAudioSession 详解【音乐播放器的配置】

前言 在 iOS 音频开发中&#xff0c;AVAudioSession 是至关重要的工具&#xff0c;它控制着应用的音频行为&#xff0c;包括播放、录音、后台支持和音频中断处理等。对于音乐播放器等音频需求强烈的应用&#xff0c;设计一个合理的 AVAudioSession 管理体系不仅能保证音频播放…

RabbitMQ是一个开源的消息代理和队列服务器

RabbitMQ是一个开源的消息代理和队列服务器&#xff0c;它基于AMQP&#xff08;Advanced Message Queuing Protocol&#xff0c;高级消息队列协议&#xff09;协议实现&#xff0c;同时也支持其他消息协议如STOMP、MQTT等。作为一个可靠的消息传递服务&#xff0c;RabbitMQ在分…

青少年CTF平台的基础题writeup

青少年CTF平台 1、文章管理系统 首先他这里有一个问号id&#xff0c;就想着使用mysql跑一下&#xff0c;但是windows的sqlmap很不给力&#xff0c;都不动&#xff0c;所以我后面换成了kali机来跑 跑一下就跑出了好多的数据库 第一次我使用ctftraining不出货&#xff0c;跑的一…

Coppelia Sim (v-REP)仿真 机器人3D相机手眼标定与实时视觉追踪 (一)

coppelia sim[V-REP]仿真实现 机器人于3D相机手眼标定与实时视觉追踪 一 标定板的制作生成标定的PDF文件PDF转为图像格式图像加载到仿真中 二 仿真场景设置加载机器人加载的控制dummy ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b48549d355d8441d8dfc20bc7ba7196…

【K8S系列】Kubernetes Pod节点CrashLoopBackOff 状态及解决方案详解【已解决】

在 Kubernetes 中&#xff0c;Pod 的状态为 CrashLoopBackOff 表示某个容器在启动后崩溃&#xff0c;Kubernetes 尝试重启该容器&#xff0c;但由于持续崩溃&#xff0c;重启的间隔时间逐渐增加。下面将详细介绍 CrashLoopBackOff 状态的原因、解决方案及相关命令的输出解释。 …

.NET Core WebApi第1讲(概念):Web基础、AJAX、JQuery

动态页面&#xff1a;数据流动 / Web服务器 / Ajax / 前后端分离 / restful风格源栈课堂一起帮https://17bang.ren/Code/261 一、Web基础 二、AJAX诞生 三、JQuery

ctfshow(262,264)--反序列化漏洞--字符串逃逸

Web262 源代码&#xff1a; index.php: error_reporting(0); class message{public $from;public $msg;public $to;public $tokenuser;public function __construct($f,$m,$t){$this->from $f;$this->msg $m;$this->to $t;} }$f $_GET[f]; $m $_GET[m]; $t $_…

虚拟现实新纪元:VR/AR技术将如何改变娱乐与教育

内容概要 在当今科技飞速发展的时代&#xff0c;虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;技术不仅让我们的娱乐体验如虎添翼&#xff0c;更为教育变革注入了新活力。这些技术的飞跃进展&#xff0c;将原本平淡无奇的场景转变为令人沉醉的沉浸…

HICP--2

在area 0的路由器只生成 area 0 的数据库&#xff0c;只在area 1 的一样。但是既在又在的生成两个 area的 LSDB 一、区域间三类LSA 在OSPF&#xff08;Open Shortest Path First&#xff09;协议中&#xff0c;区域间三类LSA&#xff08;Link-State Advertisement&#xff09…

【UE5】将2D切片图渲染为体积纹理,最终实现使用RT实时绘制体积纹理【第七篇-体积纹理绘制】

我们前几篇已经完成了渲染部分&#xff0c;现在终于开始做动态绘制功能了 之前使用的是这样一个体积雾的切片图&#xff0c;那么现在要做的就是动态编辑它 首先&#xff0c;让我们简单了解一下它是如何运作的&#xff1a; 开始绘制画布以渲染目标&#xff0c;并将材质绘制到画…

Python字幕滚动:为视频添加专业级动态效果!

Python实现由下向上滚动字幕 在数字媒体和编程领域&#xff0c;动态文本效果总能吸引观众的注意力。其中&#xff0c;滚动字幕是一种常见的视觉效果&#xff0c;经常用于视频、演示文稿和网页中。在Python中&#xff0c;我们可以通过多种方式来实现滚动字幕效果&#xff0c;比…

《2024中国泛娱乐出海洞察报告》解析,垂直且多元化方向发展!

随着以“社交”为代表的全球泛娱乐市场规模不断扩大以及用户需求不断细化&#xff0c;中国泛娱乐出海产品正朝着更加垂直化、多元化的方向发展。基于此&#xff0c;《2024中国泛娱乐出海洞察报告》深入剖析了中国泛娱乐行业出海进程以及各细分赛道出海现状及核心特征。针对中国…

qt QMediaPlaylist

QMediaPlaylist 是 Qt Multimedia 模块中的一个类&#xff0c;用于管理媒体文件的播放列表。它提供了一种方便的方式来组织和控制多媒体内容的播放&#xff0c;如音频和视频文件。 主要方法 QMediaPlaylist(00bject *parent nullptr):构造一个新的媒体播放列表对象。void add…

什么是分库分表?为什么要分库分表?什么时候需要分库分表?怎么样拆分?(数据库分库分表详解)

文章目录 1、什么是分库分表&#xff1f;1.1、分库分表的概念1.2、分库分表的方式1.2.1、垂直分库1.2.2、垂直分表1.2.3、水平分库1.2.4、水平分表 2、为什么要分库分表&#xff1f;3、什么时候需要分库分表&#xff1f;4、分库分表的数据路由4.1、数据路由的目的4.2、数据路由…