0

I am implementing a paged datagrid as proposed in this post Pagination in WPF. All works fine, but I have some checkboxes in my grid and when I try to check them, the application throws an exception because CollectionView does not allow the editing. How can I get the list of items in the current view and convert them to a list collection? I've added the following method in the public class PagingCollectionView : CollectionView class for testing:

    private void RefreshGrid()
    {
        //this._currentDataGrid.DataContext = this;   **throws exception** when clicking on 
        //this.Refresh();                             **checkbox

        List<Customer> list = this.Cast<Customer>().ToList();  //** still get the original list
        this._currentDataGrid.DataContext = list;
        this.Refresh();

        //I also tried this
        //this.Refresh();
        //List<Customer> list = this.Cast<Customer>().ToList();  //** same result
        //this._currentDataGrid.DataContext = list;
    }

Ideally I would like to just get what items the view has, at this point I am setting the items per page to 5 but I am getting all 16 of them. The PagingCollectionView works fine except that I can not check the boxes.

Community
  • 1
  • 1
jedgard
  • 868
  • 3
  • 23
  • 41
  • seems like binding issue. is it possible for you to post a working sample of your app which can reproduce the same? – pushpraj Aug 17 '14 at 01:57
  • Why don't you use an ObservablesCollection and set the DataContext of your grid to this collection? – user3596113 Aug 17 '14 at 09:37
  • The code is the same as the one in the URL i posted above, the only change is that i am passing the grid and added a method private void RefreshGrid() – jedgard Aug 18 '14 at 23:03
  • Which answer? There are two answers on the question you've linked here. – jamesSampica Aug 19 '14 at 13:30

1 Answers1

4

The PagingCollectionView from your linked post does not implement IEditableCollectionView, and so you are not able to change values in the grid.

Unfortunately, there does not seem to exist a standard paged collection view in WPF. But the PagedCollectionView for Silverlight does work, it's possible to just copy that code into your project. I suppose you could also install Silverlight SDK and add a reference to System.Windows.Data.dll. Or if you can implement IEditableCollectionView yourself, I'm sure you'd find a few takers ;).

For what looks like your best bet, you'll need all code from this page.

Test output:

My test output

ViewModel:

using System;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.Windows.Input;

namespace WpfApplication1.ViewModels
{
    public class CustomersViewModel : NotifyBase // replace NotifyBase by implementing INotifyPropertyChanged
    {
        public PagedCollectionView CustomerCollection { get; private set; }
        public int TotalPages { get { return (int)Math.Ceiling((double)CustomerCollection.ItemCount / (double)CustomerCollection.PageSize); } }
        public int PageNumber { get { return CustomerCollection.PageIndex + 1; } } 

        public ICommand MoveNextCommand { get { return GetValue(() => MoveNextCommand); } set { SetValue(() => MoveNextCommand, value); } }
        public ICommand MovePreviousCommand { get { return GetValue(() => MovePreviousCommand); } set { SetValue(() => MovePreviousCommand, value); } }

        public CustomersViewModel()
        {
            this.CustomerCollection = new PagedCollectionView(new ObservableCollection<Customer>
            {
                new Customer(true, "Michael", "Delaney"),
                new Customer(false, "James", "Ferguson"),
                new Customer(false, "Andrew", "McDonnell"),
                new Customer(true, "Sammie", "Hunnery"),
                new Customer(true, "Olivia", "Tirolio"),
                new Customer(false, "Fran", "Rockwell"),
                new Customer(false, "Andrew", "Renard"),
            });
            this.CustomerCollection.PageSize = 3;

            this.MoveNextCommand = new ActionCommand(MoveNext);
            this.MovePreviousCommand = new ActionCommand(MovePrevious);

        }

        private void MoveNext()
        {
            this.CustomerCollection.MoveToNextPage();
            OnPropertyChanged("PageNumber");
        }

        private void MovePrevious()
        {
            this.CustomerCollection.MoveToPreviousPage();
            OnPropertyChanged("PageNumber");
        }
    }

    public class Customer : NotifyBase // replace NotifyBase by implementing INotifyPropertyChanged
    {
        public bool IsActive { get { return GetValue(() => IsActive); } set { SetValue(() => IsActive, value); } }
        public string FirstName { get { return GetValue(() => FirstName); } set { SetValue(() => FirstName, value); } }
        public string LastName { get { return GetValue(() => LastName); } set { SetValue(() => LastName, value); } }

        public Customer(bool isActive, string firstName, string lastName)
        {
            this.IsActive = isActive;
            this.FirstName = firstName;
            this.LastName = lastName;
        }
    }

    public class ActionCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;
        private Action _action;

        public ActionCommand(Action action)
        {
            _action = action;
        }

        public bool CanExecute(object parameter) { return true; }

        public void Execute(object parameter)
        {
            if (_action != null)
                _action();
        }
    }
}

Xaml (note the TemplateColumn instead of CheckBoxColumn, because of this).

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:WpfApplication1.ViewModels"            
        Title="MainWindow" Height="350" Width="500">

    <Window.DataContext>
        <vm:CustomersViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <DockPanel Grid.Row="0">
            <Button Content="Previous" Command="{Binding MovePreviousCommand}" Margin="2"/>
            <Button Content="Next" Command="{Binding MoveNextCommand}" Margin="2"/>
            <TextBlock Grid.Row="0" Margin="2" VerticalAlignment="Center" HorizontalAlignment="Right" DockPanel.Dock="Right">
                <TextBlock.Text>
                    <MultiBinding StringFormat="Page {0}/{1}">
                        <Binding Path="PageNumber" />
                        <Binding Path="TotalPages" />
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
        </DockPanel>
        <DataGrid ItemsSource="{Binding CustomerCollection}" Grid.Row="1">
            <DataGrid.Columns>
                <DataGridTemplateColumn Header="Active">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding Path=IsActive, UpdateSourceTrigger=PropertyChanged}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="First Name" Width="*" Binding="{Binding FirstName}"/>
                <DataGridTextColumn Header="Last Name" Width="*" Binding="{Binding LastName}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

There seems to be a slight problem with version management (doesn't stop the code from working), so you might want to comment the first four lines in PagedCollectionView.MoveNext.

public bool MoveNext()
{
    //if (this._timestamp != this._collectionView.Timestamp)
    //{
    //    throw new InvalidOperationException(PagedCollectionViewResources.EnumeratorVersionChanged);
    //}

    switch (this._position)
Community
  • 1
  • 1
Mike Fuchs
  • 12,081
  • 6
  • 58
  • 71