Looking for PowerObjects? Don’t worry, you’re in the right place! We’ve been part of HCL for several years, and we’ve now taken the final step in our acquisition journey: moving our website to the HCL domain. Nothing else is changing – we are still fanatically focused on Microsoft Business Applications!

PowerObjects Blog 

for Microsoft Business Applications

|

WPF Paging Control for WPF Applications

Post Author: Joe D365 |

When displaying large amounts of data in a custom application built on Microsoft Dynamics CRM, it can be beneficial to use paging to improve user experience and the speed of the application. WPF controls like ListViews and GridViews don't come with a generic paging control, so it's the developer's responsibility to either create one or find a freely available version online.

Paging can be done simply and effectively, as you can see in our PowerGlobalSearch add-on.

Here, we'll demonstrate how to create a generic WPF paging control that can be used in any project. We'll cover not only how to create the control, but also how to use it as well!

First, we'll mock up what we want the control to look like. We want something simply that can fulfill our need and be reusable later on. We'll add the following controls:

  • 'First Page' button
  • 'Next Page' button
  • 'Previous Page' button
  • 'Last Page' button
  • A visual element showing us what our current page index is
  • A visual element showing us how many pages we have available

Heading over into Visual Studio, we can create a new solution or project and a new class library:

Getting started with WPF paging control

To our new project, we'll add a new WPF User Control:

We'll end up with simple looking control that looks like this:

By using the following markup:


    
        
            

You can tell by looking at it that it's a pretty simple control. You can always use custom styling or modification of the content of the buttons to get the look that you're going for.

Now, since we'll be keeping track of both a page index and a number of pages, we'll need to add a couple of dependency properties and fields. We'll jump into the code behind and add our dependencies first:

public static readonly DependencyProperty PageIndexProperty =
       DependencyProperty.Register("PageIndex", typeof(int), typeof(PagingControl));

public static readonly DependencyProperty NumberOfPagesProperty =
DependencyProperty.Register("NumberOfPages", typeof(int), typeof(PagingControl));

These dependency properties give us a way to update values on the control as they change for our data set. We'll also create a couple of public fields so that these values can be accessed at any time from the control:

public int PageIndex
{
get { return Int32.Parse(GetValue(PageIndexProperty).ToString()); }
set { SetValue(PageIndexProperty, value); }
}

public int NumberOfPages
{
get { return Int32.Parse(GetValue(NumberOfPagesProperty).ToString()); }
set { SetValue(NumberOfPagesProperty, value); }
}

Since the setup for each of the buttons will be the same, we'll just show how to wire one of them up. We'll take the 'Next Page' button as our example. You'll notice in our XAML that we already filled out an event name for our Click Event:

Let's add that event to our code behind:

private void btnLastPage_Click(object sender, RoutedEventArgs e){}

Now, what to do with this event? Well, we want to expose the event to whatever application requires it, so we'll have to create a public event and an event handler:

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

public static readonly RoutedEvent NextPageClick = EventManager.RegisterRoutedEvent(
"Next", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(PagingControl));

There! With that done, we're now ready to create an instance of it for our data control. We'll just mock up a simple view so you can see what it will look like:

And here's the code behind:


    
        
            
            
        
        
            
            
        
        
            
                
                    
                        
                            
                                
                        
                    
                    
                    
                
            
        
        
    

You can see we've simply added a ListView to our Window as well added our control to the page. In our code behind, we first create a reference to the control's assembly:

xmlns:pc="clr-namespace:PagingControl;assembly=PagingControl"

And then instantiated the control at the bottom of our page:

Keeping the idea of MVVM alive, we'll now create a ViewModel that correlates to our View. We've created a class called PagingViewModel, but you can call it whatever you like. Your new class should inherit the INotifyPropertyChanged interface, and implement it as follows:

public class PagingViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
}

Now we'll create two private fields:

private int _numberOfPages;
private int _pageIndex;

Let's create a method to raise our new PropertyChanged event if we change one of these values:

protected void OnPropertyChanged(string name)
{
var handler = PropertyChanged;
if (handler != null)
       {
           handler(this, new PropertyChangedEventArgs(name));
}
}

Now, we can utilize the OnPropertyChanged method to fire off the event in some public access methods:

public int PageIndex
{
get
{
           return _pageIndex;
}
       set
       {
           _pageIndex = value;
              OnPropertyChanged("PageIndex");
}
}

public int NumberOfPages
{
get
       {
           return _numberOfPages;
       }
       set
       {
           _numberOfPages = value;
              OnPropertyChanged("NumberOfPages");
}
}

Now, whenever we change the value of our field, an event will be triggered to notify our control that it needs to render its appearance. All that's left is to tie our exposed event handler on the control to an action on our ViewModel. First we'll add the NextPage event to our XAML:

In our Paging_NextPage method, we'd then make a service call against our ViewModel that would get new data and set those fields on our ViewModel, which would in turn fire off an event telling our control to re-render. Here are some placeholders for what it might look like:

private void Paging_NextPage(object sender, RoutedEventArgs e)
{
_viewModel.GetData();
}

On the Window control and this on the ViewModel:

public void GetData()
{
var dataReturned = _service.GetDataFromService();
       NumberOfPages = dataReturned.PageCount;
       PageIndex = dataReturned.PageIndex;
}

Now you have a working paging control that can be used for any project!

In addition to custom web applications built on Microsoft Dynamics CRM, PowerObjects helps companies and non-profit organizations build custom screens and online portals.

Happy CRM'ing!

Joe CRM
By Joe D365
Joe D365 is a Microsoft Dynamics 365 superhero who runs on pure Dynamics adrenaline. As the face of PowerObjects, Joe D365’s mission is to reveal innovative ways to use Dynamics 365 and bring the application to more businesses and organizations around the world.

One comment on “WPF Paging Control for WPF Applications”

  1. I'd just like to point out that whilst your code example will work, it is particularly elegant, and you perform event handling in the Views code-behind, which violates MVVM. You bind to events going on in the code behind of the View, rather than binding to the ViewModel. I would suggest modifying your guide (which is great may I add!) and change the routed event handlers to Commands that are then thusly bound in the View.

    E.g. In the code behind for the paging control, alter

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

    to

    public ICommand NextPageCommand
    {
    get { return (ICommand)GetValue(NextPageCommandProperty); }
    set { SetValue(NextPageCommandProperty, value); }
    }

    Set the DependencyProperty for NextPage to

    public static readonly DependencyProperty NextPageCommandProperty =
    DependencyProperty.Register("NextPageCommand", typeof(ICommand), typeof(PagingControl), new PropertyMetadata(default(ICommand)));

    In the PagingControl XAML, set the UserControl name to root

    Then bind the appropriate buttons to the commands.

    E.g.

    Finally when you create a PagingControl in XAML in one of your views, you can bind the DependencyProperties to Commands thusly:

    Code Behind in the view:

    public ICommand NextPage
    {
    get
    {
    if (_nextPageCommand == null)
    {
    _nextPageCommand = new RelayCommand(n => Next_Page());
    }
    return _nextPageCommand;
    }
    }

    void Next_Page()
    {
    // do stuff here.
    }

    Just thought I'd give something back

PowerObjects Recommends