Как я могу разбить на страницы WPF DataGrid?

Как настроить пейджинг в wpf DataGrid?


person Community    schedule 24.04.2009    source источник
comment
Пожалуйста, проверьте этот сообщение в codeproject.   -  person Shoban    schedule 24.04.2009


Ответы (1)


Приведенная выше статья о проекте кода вполне хороша для того, чтобы сделать это с таблицами ADO. В то время как для большинства приложений это, вероятно, будет отлично работать и легко понять, есть и более "WPF-дзен-подобный" способ сделать это, и это будет использование CollectionViews. Преимущество использования CollectionView по сравнению с приведенным выше примером заключается в том, что он немного более общий с точки зрения того, какие данные вы помещаете в свою сетку (не то, чтобы вы не могли сделать этот пример более общим), и он хорошо подходит. с общей моделью привязки данных WPF. Это дает вам место для поддержки общих операций, таких как сортировка, группировка и т. д., если они вам нужны.

Я собрал очень короткий пример едва работающего PagingCollectionView, привязанного к элементу управления .NET 4.0 DataGrid. Хотя сам пример довольно тривиален, он показывает вам, по крайней мере, как начать работу, поскольку у вас есть прокси вокруг фактического набора данных, с которыми вы можете выполнять простые операции, такие как MoveToNextPage и MoveToPreviousPage.

Вот C# для обработки событий Window и PagingCollectionView:

using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;

namespace GridPagingExample
{
    public partial class MainWindow : Window
    {
        private readonly PagingCollectionView _cview;

        public MainWindow()
        {
            InitializeComponent();
            this._cview = new PagingCollectionView(
                new List<object>
                {
                    new { Animal = "Lion", Eats = "Tiger" },
                    new { Animal = "Tiger", Eats =  "Bear" },
                    new { Animal = "Bear", Eats = "Oh my" },
                    new { Animal = "Wait", Eats = "Oh my isn't an animal" },
                    new { Animal = "Oh well", Eats = "Who is counting anyway" },
                    new { Animal = "Need better content", Eats = "For posting on stackoverflow" }
                },
                2
            );
            this.DataContext = this._cview;
        }

        private void OnNextClicked(object sender, RoutedEventArgs e)
        {
            this._cview.MoveToNextPage();
        }

        private void OnPreviousClicked(object sender, RoutedEventArgs e)
        {
            this._cview.MoveToPreviousPage();
        }
    }

    public class PagingCollectionView : CollectionView
    {
        private readonly IList _innerList;
        private readonly int _itemsPerPage;

        private int _currentPage = 1;

        public PagingCollectionView(IList innerList, int itemsPerPage)
            : base(innerList)
        {
            this._innerList = innerList;
            this._itemsPerPage = itemsPerPage;
        }

        public override int Count
        {
            get 
            { 
                if (this._innerList.Count == 0) return 0;
                if (this._currentPage < this.PageCount) // page 1..n-1
                {
                    return this._itemsPerPage;
                }
                else // page n
                {
                    var itemsLeft = this._innerList.Count % this._itemsPerPage;
                    if (0 == itemsLeft)
                    {
                        return this._itemsPerPage; // exactly itemsPerPage left
                    }
                    else
                    {
                        // return the remaining items
                        return itemsLeft;
                    }
                }
            }
        }

        public int CurrentPage
        {
            get { return this._currentPage; }
            set
            {
                this._currentPage = value;
                this.OnPropertyChanged(new PropertyChangedEventArgs("CurrentPage"));
            }
        }

        public int ItemsPerPage { get { return this._itemsPerPage; } }

        public int PageCount
        {
            get 
            { 
                return (this._innerList.Count + this._itemsPerPage - 1) 
                    / this._itemsPerPage; 
            }
        }

        private int EndIndex
        {
            get
            {
                var end = this._currentPage * this._itemsPerPage - 1;
                return (end > this._innerList.Count) ? this._innerList.Count : end;
            }
        }

        private int StartIndex
        {
            get { return (this._currentPage - 1) * this._itemsPerPage; }
        }

        public override object GetItemAt(int index)
        {
            var offset = index % (this._itemsPerPage); 
            return this._innerList[this.StartIndex + offset];
        }

        public void MoveToNextPage()
        {
            if (this._currentPage < this.PageCount)
            {
                this.CurrentPage += 1;
            }
            this.Refresh();
        }

        public void MoveToPreviousPage()
        {
            if (this._currentPage > 1)
            {
                this.CurrentPage -= 1;
            }
            this.Refresh();
        }
    }
}

Вот XAML для окна:

<Window x:Class="GridPagingExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Grid.Row="0">
            <Label Grid.Row="0" Margin="2">
                <Label.Content>
                    <Binding Path="CurrentPage">
                        <Binding.StringFormat>Current Page: {0}</Binding.StringFormat>
                    </Binding>
                </Label.Content>
            </Label>
            <Button Content="Next" Click="OnNextClicked" Margin="2"/>
            <Button Content="Previous" Click="OnPreviousClicked" Margin="2"/>
        </StackPanel>
        <DataGrid ItemsSource="{Binding}" Grid.Row="1">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Animal" Width="*" Binding="{Binding Animal}"/>
                <DataGridTextColumn Header="Eats" Width="*" Binding="{Binding Eats}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Вы можете создать этот CollectionView для поддержки большего количества функций, некоторые тривиальные, такие как MoveToLastPage и MoveToFirstPage, и некоторые, которые требуют дополнительных размышлений о том, как вы хотите, чтобы он вел себя, например, сортировка. Надеюсь, это полезно.

person timmyl    schedule 11.02.2011
comment
Кроме того, в Silverlight есть один из них: msdn.microsoft.com/en-us/library/, поэтому рассмотрение этого с помощью Reflector также может быть очень полезным примером для работы. Удачи! - person timmyl; 12.02.2011
comment
Кажется, в этом коде отсутствует важная часть: как заставить сетку данных отображать только ItemsPerPage, а не все элементы, верно? - person newman; 09.01.2014
comment
Silverlight работает и имеет то преимущество, что его можно редактировать. Я разместил более подробную информацию здесь: stackoverflow.com/a/25392986/385995 - person Mike Fuchs; 20.08.2014
comment
но если у меня есть 5 данных в моей базе данных, и я выбрал элементы на странице как 2, то при отображении 5-го элемента я получаю сообщение об ошибке. Как мне это решить? такая же ошибка возникает, если у меня есть 8 данных, и я выбрал элементы на странице как 3, я получаю сообщение об ошибке при отображении последних двух элементов - person wingskush; 19.01.2015
comment
Этот код подвергается исключению Index out of range, когда количество элементов меньше числа itemsPerPage. См. здесь, чтобы исправить это: stackoverflow.com/questions/25300154/wpf-datagrid-pagination - person rPulvi; 05.03.2015
comment
@Riccardo - спасибо, что указали на это. Я обновил пост, чтобы другие не попались на него. - person timmyl; 28.03.2015
comment
Кроме того, если вы хотите поддерживать пустой набор данных, вам нужна такая проверка в начале этого переопределения счетчика: if (_innerList.Count == 0) return 0; - person Yushatak; 09.04.2015
comment
Кажется, что он не поддерживает встроенное свойство Filter объекта CollectionView, который он выводит, — похоже, он его игнорирует. - person Yushatak; 09.04.2015
comment
Вы получите значительный прирост производительности (и, предположительно, меньшее количество ошибок), если замените базовый класс на ListCollectionView — обычные CollectionView используют много устаревшего поведения и больше не предназначены для создания экземпляров как есть (см. referencesource.microsoft.com/#PresentationFramework/Framework/). - person Yushatak; 09.04.2015
comment
Чтобы исправить отсутствие функции фильтрации, вы должны переопределить RefreshOverride() и выполнить там фильтрацию, чтобы повлиять на _innerList — я рекомендую использовать исходный контент ListCollectionView для этой функции в качестве руководства для этого. Это было вызвано использованием нашего собственного списка, а не встроенного CollectionView, к которому мы не можем получить доступ. - person Yushatak; 09.04.2015
comment
я использовал его, и он отлично работает. однако раньше я также страдал от проблемы с выходом за пределы диапазона, и каким-то образом я решил ее с помощью решения, которое я где-то нашел. но я заметил, что он отключает функцию сортировки по умолчанию для сетки данных. Как мне это решить? @тиммил - person wingskush; 24.04.2015
comment
@wingskush - этот пример не поддерживает сортировку. Я бы предложил использовать реализацию Microsoft из dll Silverlight, так как это более полная реализация, которая поддерживает сортировку, фильтрацию и не страдает от множества случайных ошибок. - person timmyl; 27.04.2015
comment
это должен быть элемент управления в WPF по умолчанию :-) хорошая работа, я немного повозился с ним, но только макет и немного кода. - person Zorkind; 20.02.2018
comment
@Yushatak, не могли бы вы опубликовать, как переопределить метод Refresh ()? Я тоже не могу включить фильтрацию. - person Lucy82; 07.05.2021