【6月日新计划41】WPF入门-Prism之分页查询

132 阅读3分钟

1. Diff

1.1

ObservableCollection ObservableCollection继承了Collection,INotifyCollectionChanged,INotifyPropertyChanged

  • Collection:为泛型集合提供基类

  • INotifyCollectionChanged:将集合的动态更改通知给侦听器,例:何时添加或移除项或者重置整个集合对象。

  • INotifyPropertyChanged:向客户端发出某一属性值已经更改的通知

注意:ObservableCollection表示一个动态数据集合,在添加项、移除项或刷新整个列表时,此集合将提供通知。满足MVVM模式。

1.2 List

List继承了IList,ICollection,IEnumerable,IList,ICollection,IEnumerable

  • IList:表示可按照索引单独访问的一组对象

  • ICollection:定义操作泛型集合的方法

  • IEnmerable:公开枚举器,改枚举器支持在指定类型的集合上进行简单迭代

  • IList:表示可按照索引单独访问的对象的非泛型集合

  • ICollection:定义所有非泛型集合的大小、枚举器和同步方法

  • IEnumerable:公开枚举器,该枚举器支持在非泛型集合上进行简单迭代

List表示可通过索引访问的对象的强类型列表。提供用于对列表进行搜索、排序和操作的方法。

2. Create Pager View

先創建一個UserController,名字為Pager,如下是xaml和xaml.cs

<UserControl x:Class="xxxxx.Views.Control.Pager"
             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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             xmlns:local="clr-namespace:xxxxx.Views.Control"
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             mc:Ignorable="d">
    <UserControl.Resources>
        <Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignRaisedLightButton}">
            <Setter Property="Width" Value="35"/>
            <Setter Property="Height" Value="30"/>
        </Style>
    </UserControl.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="2.5*" />
        </Grid.ColumnDefinitions>
        <StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
            <TextBlock Text="每页显示" VerticalAlignment="Center" FontWeight="Bold" Margin="4"/>
            <ComboBox Width="45" 
                      Height="30"
                      FontSize="15"
                      FontWeight="Bold"
                      Foreground="BlueViolet"
                      SelectedIndex="{Binding ComboBoxIndex, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                      Style="{StaticResource MaterialDesignComboBox}">
                <ComboBoxItem Content="20" />
                <ComboBoxItem Content="50" />
                <ComboBoxItem Content="100" />
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <i:InvokeCommandAction Command="{Binding ComboBoxSelectChange}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ComboBox>
            <TextBlock Text="条" VerticalAlignment="Center" FontWeight="Bold" Margin="4"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Grid.Column="1">
            <Button x:Name="FirstPageButton" Margin="10" Click="FirstPageButton_Click" Style="{StaticResource MaterialDesignRaisedLightButton}">
                <materialDesign:PackIcon Kind="ArrowCollapseLeft" Height="20" Width="20"/>
            </Button>
            <Button x:Name="PreviousPageButton" Margin="10" Click="PreviousPageButton_Click" Style="{StaticResource MaterialDesignRaisedLightButton}">
                <materialDesign:PackIcon Kind="ArrowLeft" Height="20" Width="20"/>
            </Button>
            <TextBlock VerticalAlignment="Center" FontWeight="Bold">
                <Run Text="第"/>
                <Run x:Name="rCurrent" Text="0"/>
                <Run Text="页"/>
            </TextBlock>
            <Button Margin="10" x:Name="NextPageButton" Click="NextPageButton_Click" Style="{StaticResource MaterialDesignRaisedLightButton}">
                <materialDesign:PackIcon Kind="ArrowRight" Height="20" Width="20"/>
            </Button>
            <Button Margin="10" x:Name="LastPageButton" Click="LastPageButton_Click" Style="{StaticResource MaterialDesignRaisedLightButton}">
                <materialDesign:PackIcon Kind="ArrowCollapseRight" Height="20" Width="20"/>
            </Button>
            <TextBlock VerticalAlignment="Center" FontWeight="Bold">
                <Run Text="共"/>
                <Run x:Name="rTotal" Text="0"/>
                <Run Text="页"/>
            </TextBlock>
        </StackPanel>
    </Grid>
</UserControl>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 xxxxx.Views.Control
{
    /// <summary>
    /// Pager.xaml 的互動邏輯
    /// </summary>
    public partial class Pager : UserControl
    {
        public static RoutedEvent FirstPageEvent;
        public static RoutedEvent PreviousPageEvent;
        public static RoutedEvent NextPageEvent;
        public static RoutedEvent LastPageEvent;

        public static readonly DependencyProperty CurrentPageProperty;
        public static readonly DependencyProperty TotalPageProperty;

        public string CurrentPage
        {
            get { return (string)GetValue(CurrentPageProperty); }
            set { SetValue(CurrentPageProperty, value); }
        }

        public string TotalPage
        {
            get { return (string)GetValue(TotalPageProperty); }
            set { SetValue(TotalPageProperty, value); }
        }

        public Pager()
        {
            InitializeComponent();
        }

        static Pager()
        {
            FirstPageEvent = EventManager.RegisterRoutedEvent("FirstPage", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(Pager));
            PreviousPageEvent = EventManager.RegisterRoutedEvent("PreviousPage", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(Pager));
            NextPageEvent = EventManager.RegisterRoutedEvent("NextPage", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(Pager));
            LastPageEvent = EventManager.RegisterRoutedEvent("LastPage", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(Pager));

            CurrentPageProperty = DependencyProperty.Register("CurrentPage", typeof(string), typeof(Pager), new PropertyMetadata(string.Empty,new PropertyChangedCallback(OnCurrentPageChanged)));
            TotalPageProperty = DependencyProperty.Register("TotalPage", typeof(string), typeof(Pager), new PropertyMetadata(string.Empty,new PropertyChangedCallback(OnTotalPageChanged)));
        }

        public event RoutedEventHandler FirstPage
        {
            add { AddHandler(FirstPageEvent, value); }
            remove { RemoveHandler(FirstPageEvent, value); }
        }

        public event RoutedEventHandler PreviousPage
        {
            add { AddHandler(PreviousPageEvent, value); }
            remove { RemoveHandler(PreviousPageEvent, value); }
        }

        public event RoutedEventHandler NextPage
        {
            add { AddHandler(NextPageEvent, value); }
            remove { RemoveHandler(NextPageEvent, value); }
        }

        public event RoutedEventHandler LastPage
        {
            add { AddHandler(LastPageEvent, value); }
            remove { RemoveHandler(LastPageEvent, value); }
        }

        public static void OnTotalPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Pager p = d as Pager;

            if(p != null)
            {
                Run rTotal = (Run)p.FindName("rTotal");

                rTotal.Text = (string)e.NewValue;
            }
        }

        private static void OnCurrentPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Pager p = d as Pager;

            if(p != null)
            {
                Run rCurrrent = (Run)p.FindName("rCurrent");

                rCurrrent.Text = (string)e.NewValue;
            }
        }

        private void FirstPageButton_Click(object sender, RoutedEventArgs e)
        {
            RaiseEvent(new RoutedEventArgs(FirstPageEvent, this));
        }

        private void PreviousPageButton_Click(object sender, RoutedEventArgs e)
        {
            RaiseEvent(new RoutedEventArgs(PreviousPageEvent, this));
        }

        private void NextPageButton_Click(object sender, RoutedEventArgs e)
        {
            RaiseEvent(new RoutedEventArgs(NextPageEvent, this));
        }

        private void LastPageButton_Click(object sender, RoutedEventArgs e)
        {
            RaiseEvent(new RoutedEventArgs(LastPageEvent, this));
        }
    }
}

3.Create PageList View/ViewModel

PageListView中引入前面的Pager

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ScrollViewer VerticalScrollBarVisibility="Hidden">
            <DataGrid ItemsSource="{Binding ResultFakeSource,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 
                      AutoGenerateColumns="False" 
                      CanUserAddRows="False"
                      Margin="10"
                      Height="500">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Item Id" Binding="{Binding ItemId}" Width="80"/>
                    <DataGridTextColumn Header="Item Name" Binding="{Binding ItemName}" Width="180"/>
                </DataGrid.Columns>
            </DataGrid>
        </ScrollViewer>
        <local:Pager TotalPage="{Binding TotalPage}"
                     CurrentPage="{Binding CurrentPage, Mode=TwoWay}" 
                     HorizontalAlignment="Center"
                     Margin="0,20,0,0"
                     Grid.Row="1">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="FirstPage">
                    <i:InvokeCommandAction Command="{Binding FirstPageCommand}" />
                </i:EventTrigger>
                <i:EventTrigger EventName="PreviousPage">
                    <i:InvokeCommandAction Command="{Binding PreviousPageCommand}"/>
                </i:EventTrigger>
                <i:EventTrigger EventName="NextPage">
                    <i:InvokeCommandAction Command="{Binding NextPageCommand}" />
                </i:EventTrigger>
                <i:EventTrigger EventName="LastPage">
                    <i:InvokeCommandAction Command="{Binding LastPageCommand}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </local:Pager>
    </Grid>
using ImTools;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace xxxxx.ViewModels.LeftViewModel
{
    public class PageListViewModel : BindableBase
    {

        private readonly IEventAggregator aggregator;

        #region Command
        public DelegateCommand FirstPageCommand { get; set; }

        public DelegateCommand PreviousPageCommand { get; set; }

        public DelegateCommand NextPageCommand { get; set; }

        public DelegateCommand LastPageCommand { get; set; }

        public DelegateCommand ComboBoxSelectChange { get; set; }


        #endregion

        #region  Parameter

        private int totalPage;

        public int TotalPage
        {
            get { return totalPage; }
            set { totalPage = value; RaisePropertyChanged(); }
        }

        private int currentPage;

        public int CurrentPage
        {
            get { return currentPage; }
            set { currentPage = value; RaisePropertyChanged(); }
        }

        private int pageSize;

        public int PageSize
        {
            get { return pageSize; }
            set { pageSize = value; RaisePropertyChanged(); }
        }


        private int comboBoxIndex = 0;

        public int ComboBoxIndex
        {
            get { return comboBoxIndex; }
            set { comboBoxIndex = value; RaisePropertyChanged(); }
        }



        private ObservableCollection<FakeDatabase> fakeSource;

        public ObservableCollection<FakeDatabase> FakeSource
        {
            get { return fakeSource; }
            set { fakeSource = value; RaisePropertyChanged(); }
        }

        private ObservableCollection<FakeDatabase> resultFakeSource;

        public ObservableCollection<FakeDatabase> ResultFakeSource
        {
            get { return resultFakeSource; }
            set { resultFakeSource = value; RaisePropertyChanged(); }
        }

        #endregion

        public PageListViewModel(IEventAggregator aggregator)
        {
            this.aggregator = aggregator;

            FakeSource = new ObservableCollection<FakeDatabase>();
            ResultFakeSource = new ObservableCollection<FakeDatabase>();
            InitialLoad();

            ComboBoxSelectAction();

            FirstPageCommand = new DelegateCommand(FirstPageAction);

            PreviousPageCommand = new DelegateCommand(PreviousPageAction);

            NextPageCommand = new DelegateCommand(NextPageAction);

            LastPageCommand = new DelegateCommand(LastPageAction);
            ComboBoxSelectChange = new DelegateCommand(ComboBoxSelectAction);
        }

        private void ComboBoxSelectAction()
        {
            aggregator.UpdateLoading(true);
            CurrentPage = 1;

            switch (ComboBoxIndex)
            {
                case 0:
                    PageSize = 20;
                    break;
                case 1:
                    PageSize = 50;
                    break;
                case 2:
                    PageSize = 100;
                    break;
            }
            System.Diagnostics.Trace.WriteLine(pageSize);
            TotalPage = FakeSource.Count / PageSize;

            //点击事件
            var result = FakeSource.Take(PageSize).ToList();
            ResultFakeSource.Clear();
            ResultFakeSource.AddRange(result);
            aggregator.UpdateLoading(false);
        }

        private async void FirstPageAction()
        {
            aggregator.UpdateLoading(true);
            CurrentPage = 1;

            var result = FakeSource.Take(PageSize).ToList();

            await Task.Delay(450);
            ResultFakeSource.Clear();
            ResultFakeSource.AddRange(result);

            aggregator.UpdateLoading(false);
        }

        private async void PreviousPageAction()
        {
            aggregator.UpdateLoading(true);
            if (CurrentPage == 1)
            {
                return;
            }

            List<FakeDatabase> result = new List<FakeDatabase>();
            if (CurrentPage == 2)
            {
                result = FakeSource.Take(PageSize).ToList();

            }
            else
            {
                result = FakeSource.Skip((CurrentPage - 2) * PageSize).Take(pageSize).ToList();
            }

            await Task.Delay(450);
            ResultFakeSource.Clear();
            ResultFakeSource.AddRange(result);
            CurrentPage--;

            aggregator.UpdateLoading(false);
        }

        private async void NextPageAction()
        {
            aggregator.UpdateLoading(true);

            if (CurrentPage == TotalPage)
            {
                return;
            }

            var result = FakeSource.Skip(CurrentPage * PageSize).Take(PageSize).ToList();

            await Task.Delay(450);
            ParseList(result);
            ResultFakeSource.Clear();
            ResultFakeSource.AddRange(result);
            CurrentPage++;

            aggregator.UpdateLoading(false);
        }

        private async void LastPageAction()
        {
            aggregator.UpdateLoading(true);
            CurrentPage = TotalPage;

            int skipCount = (TotalPage - 1) * PageSize;
            int takeCount = FakeSource.Count - skipCount;

            var result = FakeSource.Skip(skipCount).Take(takeCount).ToList();
            await Task.Delay(450);
            ResultFakeSource.Clear();
            ResultFakeSource.AddRange(result);

            aggregator.UpdateLoading(false);
        }

        public void InitialLoad()
        {
            for (int i = 0; i < 1000; i++)
            {

                FakeSource.Add(new FakeDatabase { ItemId = i, ItemName = "Demo_Page_" + i });
            }
        }

        public void ParseList(List<FakeDatabase> result)
        {

            for (int i = 0; i < result.Count; i++)
            {
                FakeDatabase db = result[i];
                System.Diagnostics.Trace.WriteLine(db.ItemId + "==" + db.ItemName);
            }

        }
    }
}