The otro día escribí una clase PagingController
para ayudar con la paginación, así que aquí voy:
va a tener que limpiar las fuentes un poco b ebido al hacer algún uso de los contratos MS Código, que hacen referencia a algunas cosas de utilidad (muy básico) del prisma, etc.
Ejemplo de uso (código subyacente - ViewModel.cs
):
private const int PageSize = 20;
private static readonly SortDescription DefaultSortOrder = new SortDescription("Id", ListSortDirection.Ascending);
private readonly ObservableCollection<Reservation> reservations = new ObservableCollection<Reservation>();
private readonly CollectionViewSource reservationsViewSource = new CollectionViewSource();
public ViewModel()
{
this.reservationsViewSource.Source = this.reservations;
var sortDescriptions = (INotifyCollectionChanged)this.reservationsViewSource.View.SortDescriptions;
sortDescriptions.CollectionChanged += this.OnSortOrderChanged;
// The 5000 here is the total number of reservations
this.Pager = new PagingController(5000, PageSize);
this.Pager.CurrentPageChanged += (s, e) => this.UpdateData();
this.UpdateData();
}
public PagingController Pager { get; private set; }
public ICollectionView Reservations
{
get { return this.reservationsViewSource.View; }
}
private void UpdateData()
{
var currentSort = this.reservationsViewSource.View.SortDescriptions.DefaultIfEmpty(DefaultSortOrder).ToArray();
// This is the "fetch the data" method, the implementation of which
// does not directly interest us for this example.
var data = this.crsService.GetReservations(this.Pager.CurrentPageStartIndex, this.Pager.PageSize, currentSort);
this.reservations.Clear();
this.reservations.AddRange(data);
}
private void OnSortOrderChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add) {
this.UpdateData();
}
}
Ejemplo de uso (XAML - View.xaml
):
<DataGrid ... ItemSource="{Binding Reservations}" />
<!-- all the rest is UI to interact with the pager -->
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="4">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="FontFamily" Value="Webdings" />
<Setter Property="Width" Value="60" />
<Setter Property="Margin" Value="4,0,4,0" />
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="4,0,4,0" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="4,0,4,0" />
<Setter Property="Width" Value="40" />
</Style>
</StackPanel.Resources>
<Button Content="9" Command="{Binding Path=Pager.GotoFirstPageCommand}" />
<Button Content="3" Command="{Binding Path=Pager.GotoPreviousPageCommand}" />
<TextBlock Text="Page" />
<TextBox Text="{Binding Path=Pager.CurrentPage, ValidatesOnExceptions=True}" />
<TextBlock Text="{Binding Path=Pager.PageCount, StringFormat=of {0}}" />
<Button Content="4" Command="{Binding Path=Pager.GotoNextPageCommand}" />
<Button Content=":" Command="{Binding Path=Pager.GotoLastPageCommand}" />
</StackPanel>
<ScrollBar Orientation="Horizontal" Minimum="1" Maximum="{Binding Path=Pager.PageCount}" Value="{Binding Path=Pager.CurrentPage}"/>
</StackPanel>
Breve explicación:
Como ve, el ViewModel realmente no hace mucho. Mantiene una colección de elementos que representan la página actual y expone un CollectionView
(para el enlace de datos) y un PagingController
en la Vista. Entonces todo lo que hace es actualizar los elementos de datos en la colección (y por consiguiente en el CollectionView
) cada vez que el PagingController
indica que algo ha cambiado. Por supuesto, esto significa que necesita un método que, dado un índice inicial, un tamaño de página, y un SortDescription[]
devuelve la porción de datos descrita por estos parámetros. Esto es parte de su lógica comercial, y no he incluido código para eso aquí.
En el lado XAML todo el trabajo se realiza mediante el enlace al PagingController
.He expuesto la funcionalidad completa aquí (botones vinculados a los comandos Primero/Anterior/Siguiente/Último, enlace directo de TextBox
a CurrentPage
y enlace de ScrollBar
a). Por lo general, no usarás todo esto al mismo tiempo.
¡Gracias Jon, muy apreciado! – Aaron
¿Funcionaría esto para un DataGrid que cambia el tamaño (y por lo tanto cambia la cantidad de elementos visibles? –
@ChrisKlepeis: no como se da pero puede vincularse a 'PageSize' y registrarse para' PropertyChanged', así que no veo cualquier cosa que se destaque allí. Por supuesto, el buscapersonas no estaba destinado a cubrir eficazmente este caso, por lo que perf no será tan bueno como podría ser. – Jon