< Summary

Information
Class: MyNet.UI.ViewModels.List.Paging.PagingViewModel
Assembly: MyNet.UI
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.UI/ViewModels/List/Paging/PagingViewModel.cs
Tag: 323_28699572109
Line coverage
95%
Covered lines: 43
Uncovered lines: 2
Coverable lines: 45
Total lines: 204
Line coverage: 95.5%
Branch coverage
65%
Covered branches: 17
Total branches: 26
Branch coverage: 65.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
set_PageSize(...)50%2275%
set_CurrentPage(...)100%22100%
set_TotalPages(...)100%22100%
set_TotalItems(...)100%11100%
get_HasNextPage()100%11100%
get_HasPreviousPage()100%11100%
MoveToPage(...)50%7675%
MoveNext()100%11100%
MovePrevious()100%11100%
MoveFirst()100%11100%
MoveLast()100%11100%
Update(...)75%44100%
RequestPage(...)100%11100%
RaisePagingChanged()100%22100%
RaiseNavigationCommandsCanExecuteChanged()50%88100%
OnPageSizeChanged()100%11100%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.UI/ViewModels/List/Paging/PagingViewModel.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="PagingViewModel.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Windows.Input;
 9using MyNet.Observable;
 10using MyNet.UI.Commands;
 11using MyNet.Utilities.Deferring;
 12
 13namespace MyNet.UI.ViewModels.List.Paging;
 14
 15/// <summary>
 16/// ViewModel for managing paging state and navigation in a paginated list or collection.
 17/// </summary>
 18public class PagingViewModel : ObservableObject, IPagingViewModel
 19{
 20    private readonly DeferredAction _deferredAction;
 21
 22    /// <summary>
 23    /// Initializes a new instance of the <see cref="PagingViewModel"/> class with an optional page size.
 24    /// </summary>
 25    /// <param name="pageSize">The number of items per page.</param>
 26    /// <param name="commandFactory">Optional command factory used to create commands.</param>
 6027    public PagingViewModel(int pageSize = 25, ICommandFactory? commandFactory = null)
 28    {
 6029        var commands = commandFactory.GetOrDefault();
 30
 6031        _deferredAction = new(RaisePagingChanged);
 32
 33        MoveNextCommand = commands.Create(MoveNext, () => HasNextPage);
 34        MovePreviousCommand = commands.Create(MovePrevious, () => HasPreviousPage);
 35        MoveFirstCommand = commands.Create(MoveFirst, () => HasPreviousPage);
 36        MoveLastCommand = commands.Create(MoveLast, () => HasNextPage);
 37
 6038        PageSize = pageSize;
 6039    }
 40
 41    /// <summary>
 42    /// Gets or sets the number of items per page.
 43    /// Changing this property triggers a <see cref="PagingChanged"/> event.
 44    /// </summary>
 45    public int PageSize
 46    {
 47        get;
 48        set
 49        {
 6050            if (!SetProperty(ref field, value))
 051                return;
 52
 6053            OnPageSizeChanged();
 6054        }
 55    }
 56
 57    /// <summary>
 58    /// Gets the current page number (1-based index).
 59    /// Updated via <see cref="Update"/> method or navigation commands.
 60    /// </summary>
 61    public int CurrentPage
 62    {
 63        get;
 64        private set
 65        {
 18066            if (!SetProperty(ref field, value))
 13867                return;
 68
 4269            NotifyPropertyChanged(nameof(HasNextPage));
 4270            NotifyPropertyChanged(nameof(HasPreviousPage));
 4271            RaiseNavigationCommandsCanExecuteChanged();
 4272        }
 73    }
 74
 75        = 1;
 76
 77    /// <summary>
 78    /// Gets the total number of pages based on <see cref="TotalItems"/> and <see cref="PageSize"/>.
 79    /// Updated via <see cref="Update"/> method.
 80    /// </summary>
 81    public int TotalPages
 82    {
 83        get;
 84        private set
 85        {
 9686            if (!SetProperty(ref field, value))
 3387                return;
 88
 6389            NotifyPropertyChanged(nameof(HasNextPage));
 6390            RaiseNavigationCommandsCanExecuteChanged();
 6391        }
 92    }
 93
 94    /// <summary>
 95    /// Gets the total number of items across all pages.
 96    /// Updated via <see cref="Update"/> method.
 97    /// </summary>
 98    public int TotalItems
 99    {
 100        get;
 96101        private set => SetProperty(ref field, value);
 102    }
 103
 104    /// <summary>
 105    /// Gets a value indicating whether there is a next page available.
 106    /// </summary>
 27107    public bool HasNextPage => CurrentPage < TotalPages;
 108
 109    /// <summary>
 110    /// Gets a value indicating whether there is a previous page available.
 111    /// </summary>
 21112    public bool HasPreviousPage => CurrentPage > 1;
 113
 114    /// <inheritdoc />
 115    public ICommand MoveNextCommand { get; }
 116
 117    /// <inheritdoc />
 118    public ICommand MovePreviousCommand { get; }
 119
 120    /// <inheritdoc />
 121    public ICommand MoveFirstCommand { get; }
 122
 123    /// <inheritdoc />
 124    public ICommand MoveLastCommand { get; }
 125
 126    /// <summary>
 127    /// Occurs when the paging configuration has changed (page number or page size).
 128    /// </summary>
 129    public event EventHandler<PagingChangedEventArgs>? PagingChanged;
 130
 131    /// <summary>
 132    /// Moves to the specified page number (1-based).
 133    /// Raises the <see cref="PagingChanged"/> event if the page is valid and different from the current page.
 134    /// </summary>
 135    /// <param name="page">The target page number (must be between 1 and <see cref="TotalPages"/>).</param>
 136    public void MoveToPage(int page)
 137    {
 24138        if (page < 1 || page > TotalPages || page == CurrentPage)
 0139            return;
 140
 24141        RequestPage(page);
 24142    }
 143
 144    /// <summary>
 145    /// Moves to the next page if not on the last page.
 146    /// </summary>
 9147    public void MoveNext() => MoveToPage(CurrentPage + 1);
 148
 149    /// <summary>
 150    /// Moves to the previous page if not on the first page.
 151    /// </summary>
 3152    public void MovePrevious() => MoveToPage(CurrentPage - 1);
 153
 154    /// <summary>
 155    /// Moves to the first page.
 156    /// </summary>
 3157    public void MoveFirst() => MoveToPage(1);
 158
 159    /// <summary>
 160    /// Moves to the last page.
 161    /// </summary>
 3162    public void MoveLast() => MoveToPage(TotalPages);
 163
 164    /// <summary>
 165    /// Updates the paging state based on a response from a paging operation.
 166    /// </summary>
 167    /// <param name="totalItems">The total number of items across all pages.</param>
 168    /// <param name="currentPage">The current page number (1-based index).</param>
 169    public void Update(int totalItems, int currentPage)
 170    {
 96171        TotalItems = totalItems;
 96172        TotalPages = PageSize <= 0 ? 0 : (int)Math.Ceiling((double)totalItems / PageSize);
 96173        CurrentPage = TotalPages == 0 ? 1 : Math.Min(Math.Max(1, currentPage), TotalPages);
 96174    }
 175
 176    /// <summary>
 177    /// Requests a page change to the specified page number.
 178    /// </summary>
 179    /// <param name="page">The target page number (must be between 1 and <see cref="TotalPages"/>).</param>
 180    private void RequestPage(int page)
 181    {
 84182        CurrentPage = page;
 84183        _deferredAction.Request();
 84184    }
 185
 186    /// <summary>
 187    /// Invoked when the paging configuration has changed (page number or page size).
 188    /// </summary>
 84189    private void RaisePagingChanged() => PagingChanged?.Invoke(this, new(CurrentPage, PageSize));
 190
 191    private void RaiseNavigationCommandsCanExecuteChanged()
 192    {
 105193        (MoveNextCommand as IRaiseCanExecuteChanged)?.RaiseCanExecuteChanged();
 105194        (MovePreviousCommand as IRaiseCanExecuteChanged)?.RaiseCanExecuteChanged();
 105195        (MoveFirstCommand as IRaiseCanExecuteChanged)?.RaiseCanExecuteChanged();
 105196        (MoveLastCommand as IRaiseCanExecuteChanged)?.RaiseCanExecuteChanged();
 105197    }
 198
 199    /// <summary>
 200    /// Invoked when the page size has changed.
 201    /// </summary>
 60202    protected virtual void OnPageSizeChanged() => RequestPage(1);
 203}
 204