anagram4wander / VirtualizingObservableCollection

.NET PCL With Virtualizing Observable Collection
http://alphachitech.wordpress.com/2015/01/31/virtualizing-observable-collection/
56 stars 28 forks source link

All items being loaded #8

Open bjvanhaaff opened 9 years ago

bjvanhaaff commented 9 years ago

Hi

Implemented the solution in an EF based project. However, when setting my DataGrid's ItemsSource. It first requests the count which is okay but then all items are being loaded (continuously calling GetItemsAt()) from the database with the following callstack

...
AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager<TC.Client.Telecard.TelecardListViewModel>.FillPage(AlphaChiTech.Virtualization.ISourcePage<TC.Client.Telecard.TelecardListViewModel> newPage, int pageOffset) Line 754    C#
    AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager<TC.Client.Telecard.TelecardListViewModel>.SafeGetPage(int page, bool allowPlaceholders, object voc, int index) Line 1069  C#
    AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager<TC.Client.Telecard.TelecardListViewModel>.GetAt(int index, object voc, bool usePlaceholder) Line 733  C#
    AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.VirtualizingObservableCollection<TC.Client.Telecard.TelecardListViewModel>.InternalGetValue(int index, string selectionContext) Line 785    C#
    AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.VirtualizingObservableCollection<TC.Client.Telecard.TelecardListViewModel>.this[int].get(int index) Line 366    C#
    PresentationFramework.dll!System.Windows.Data.ListCollectionView.PrepareLocalArray()    Unknown
    PresentationFramework.dll!System.Windows.Data.ListCollectionView.RefreshOverride()  Unknown
    PresentationFramework.dll!System.Windows.Data.CollectionView.RefreshInternal()  Unknown
    PresentationFramework.dll!System.Windows.Data.CollectionView.Refresh()  Unknown
    PresentationFramework.dll!System.Windows.Data.CollectionView.EndDefer() Unknown
    PresentationFramework.dll!System.Windows.Data.CollectionView.DeferHelper.Dispose()  Unknown
    PresentationFramework.dll!System.Windows.Controls.ItemCollection.SetCollectionView(System.Windows.Data.CollectionView view) Unknown
    PresentationFramework.dll!System.Windows.Controls.ItemCollection.SetItemsSource(System.Collections.IEnumerable value, System.Func<object,object> GetSourceItem) Unknown
    PresentationFramework.dll!System.Windows.Controls.ItemsControl.OnItemsSourceChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e) Unknown
    WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)  Unknown
    PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)    Unknown
    WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args)    Unknown
    WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType) Unknown
    WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal)    Unknown
    WindowsBase.dll!System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty dp, object value)    Unknown
    PresentationFramework.dll!System.Windows.Controls.ItemsControl.ItemsSource.set(System.Collections.IEnumerable value)    Unknown
...

Any clues why this could be happening?

Thanks a lot

anagram4wander commented 9 years ago

Yes - try pulling a height limit on the data grid... It's probably in a stack panel so is just taking as much size as it wants...

On Sep 8, 2015, at 12:48 AM, bjvanhaaff notifications@github.com wrote:

Hi

Implemented the solution in an EF based project. However, when setting my DataGrid's ItemsSource. It first requests the count which is okay but then all items are being loaded (continuously calling GetItemsAt()) from the database with the following callstack

... AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager.FillPage(AlphaChiTech.Virtualization.ISourcePage newPage, int pageOffset) Line 754 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager.SafeGetPage(int page, bool allowPlaceholders, object voc, int index) Line 1069 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager.GetAt(int index, object voc, bool usePlaceholder) Line 733 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.VirtualizingObservableCollection.InternalGetValue(int index, string selectionContext) Line 785 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.VirtualizingObservableCollection.this[int].get(int index) Line 366 C# PresentationFramework.dll!System.Windows.Data.ListCollectionView.PrepareLocalArray() Unknown PresentationFramework.dll!System.Windows.Data.ListCollectionView.RefreshOverride() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.RefreshInternal() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.Refresh() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.EndDefer() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.DeferHelper.Dispose() Unknown PresentationFramework.dll!System.Windows.Controls.ItemCollection.SetCollectionView(System.Windows.Data.CollectionView view) Unknown PresentationFramework.dll!System.Windows.Controls.ItemCollection.SetItemsSource(System.Collections.IEnumerable value, System.Func<object,object> GetSourceItem) Unknown PresentationFramework.dll!System.Windows.Controls.ItemsControl.OnItemsSourceChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e) Unknown WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Unknown PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Unknown WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) Unknown WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType) Unknown WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal) Unknown WindowsBase.dll!System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty dp, object value) Unknown PresentationFramework.dll!System.Windows.Controls.ItemsControl.ItemsSource.set(System.Collections.IEnumerable value) Unknown ... Any clues why this could be happening?

Thanks a lot

— Reply to this email directly or view it on GitHub.

bjvanhaaff commented 9 years ago

Hi ,I tried setting MaxHeight="1024" but it made no difference. The columns in my DataGrid are being populated dynamically from within the code behind, so AutoGenerateColumns = false in my case. I found out that when I let the grid generate the columns, the issue is not happening. So it has something to do with adding the columns in code with grid.Columns.Add() …

From: anagram4wander [mailto:notifications@github.com] Sent: dinsdag 8 september 2015 16:09 To: anagram4wander/VirtualizingObservableCollection Cc: bjvanhaaff Subject: Re: [VirtualizingObservableCollection] All items being loaded (#8)

Yes - try pulling a height limit on the data grid... It's probably in a stack panel so is just taking as much size as it wants...

On Sep 8, 2015, at 12:48 AM, bjvanhaaff notifications@github.com wrote:

Hi

Implemented the solution in an EF based project. However, when setting my DataGrid's ItemsSource. It first requests the count which is okay but then all items are being loaded (continuously calling GetItemsAt()) from the database with the following callstack

... AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager.FillPage(AlphaChiTech.Virtualization.ISourcePage newPage, int pageOffset) Line 754 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager.SafeGetPage(int page, bool allowPlaceholders, object voc, int index) Line 1069 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager.GetAt(int index, object voc, bool usePlaceholder) Line 733 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.VirtualizingObservableCollection.InternalGetValue(int index, string selectionContext) Line 785 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.VirtualizingObservableCollection.this[int].get(int index) Line 366 C# PresentationFramework.dll!System.Windows.Data.ListCollectionView.PrepareLocalArray() Unknown PresentationFramework.dll!System.Windows.Data.ListCollectionView.RefreshOverride() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.RefreshInternal() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.Refresh() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.EndDefer() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.DeferHelper.Dispose() Unknown PresentationFramework.dll!System.Windows.Controls.ItemCollection.SetCollectionView(System.Windows.Data.CollectionView view) Unknown PresentationFramework.dll!System.Windows.Controls.ItemCollection.SetItemsSource(System.Collections.IEnumerable value, System.Func<object,object> GetSourceItem) Unknown PresentationFramework.dll!System.Windows.Controls.ItemsControl.OnItemsSourceChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e) Unknown WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Unknown PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Unknown WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) Unknown WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType) Unknown WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal) Unknown WindowsBase.dll!System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty dp, object value) Unknown PresentationFramework.dll!System.Windows.Controls.ItemsControl.ItemsSource.set(System.Collections.IEnumerable value) Unknown ... Any clues why this could be happening?

Thanks a lot

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHub https://github.com/anagram4wander/VirtualizingObservableCollection/issues/8#issuecomment-138570679 . https://github.com/notifications/beacon/AMBbOwRflrmlNFi1wB6RtbQZqoYIf_Usks5ovuOVgaJpZM4F5TsW.gif

anagram4wander commented 9 years ago

Try doing the column add before setting the item source..

Sent from my iPhone

On Sep 8, 2015, at 7:55 AM, bjvanhaaff notifications@github.com wrote:

Hi ,I tried setting MaxHeight="1024" but it made no difference. The columns in my DataGrid are being populated dynamically from within the code behind, so AutoGenerateColumns = false in my case. I found out that when I let the grid generate the columns, the issue is not happening. So it has something to do with adding the columns in code with grid.Columns.Add() …

From: anagram4wander [mailto:notifications@github.com] Sent: dinsdag 8 september 2015 16:09 To: anagram4wander/VirtualizingObservableCollection Cc: bjvanhaaff Subject: Re: [VirtualizingObservableCollection] All items being loaded (#8)

Yes - try pulling a height limit on the data grid... It's probably in a stack panel so is just taking as much size as it wants...

On Sep 8, 2015, at 12:48 AM, bjvanhaaff notifications@github.com wrote:

Hi

Implemented the solution in an EF based project. However, when setting my DataGrid's ItemsSource. It first requests the count which is okay but then all items are being loaded (continuously calling GetItemsAt()) from the database with the following callstack

... AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager.FillPage(AlphaChiTech.Virtualization.ISourcePage newPage, int pageOffset) Line 754 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager.SafeGetPage(int page, bool allowPlaceholders, object voc, int index) Line 1069 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.PaginationManager.GetAt(int index, object voc, bool usePlaceholder) Line 733 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.VirtualizingObservableCollection.InternalGetValue(int index, string selectionContext) Line 785 C# AlphaChiTech.Virtualization.dll!AlphaChiTech.Virtualization.VirtualizingObservableCollection.this[int].get(int index) Line 366 C# PresentationFramework.dll!System.Windows.Data.ListCollectionView.PrepareLocalArray() Unknown PresentationFramework.dll!System.Windows.Data.ListCollectionView.RefreshOverride() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.RefreshInternal() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.Refresh() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.EndDefer() Unknown PresentationFramework.dll!System.Windows.Data.CollectionView.DeferHelper.Dispose() Unknown PresentationFramework.dll!System.Windows.Controls.ItemCollection.SetCollectionView(System.Windows.Data.CollectionView view) Unknown PresentationFramework.dll!System.Windows.Controls.ItemCollection.SetItemsSource(System.Collections.IEnumerable value, System.Func<object,object> GetSourceItem) Unknown PresentationFramework.dll!System.Windows.Controls.ItemsControl.OnItemsSourceChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e) Unknown WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Unknown PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Unknown WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) Unknown WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType) Unknown WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal) Unknown WindowsBase.dll!System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty dp, object value) Unknown PresentationFramework.dll!System.Windows.Controls.ItemsControl.ItemsSource.set(System.Collections.IEnumerable value) Unknown ... Any clues why this could be happening?

Thanks a lot

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHub https://github.com/anagram4wander/VirtualizingObservableCollection/issues/8#issuecomment-138570679 . https://github.com/notifications/beacon/AMBbOwRflrmlNFi1wB6RtbQZqoYIf_Usks5ovuOVgaJpZM4F5TsW.gif

— Reply to this email directly or view it on GitHub.

bjvanhaaff commented 9 years ago

I already do that, but it was not the cause anyway. In the code a default sort order was set using TheDataGrid.Items.SortDescriptions.Add(...). this causes the grid to access all items as soon as ItemsSource is set. Initial loading is solved now but i still have an issue with refreshing/sorting. When calling VirtualizingObservableCollection.Clear() (like in your example), the first time it works okay but the second time this method is invoked, all items are being retrieved. I can send you a small program to demonstrate this if needed (main code is below). My real data originates from a EF based datasource and I'm using Take() and Skip() to fetch the right data form a sorted/filtered dataset. It's also not clear to me how to implement IndexOf() with EF and I guess I need this to keep the selected row in the DataGrid when the data is refreshed.

Thank you for your assistance.

using AlphaChiTech.Virtualization;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;

using System.Windows.Threading;

namespace VirtualizingObservableCollection {

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {

        private VirtualizingObservableCollection<Customer> _myDataVirtualized = null;

        public MainWindow() {
            InitializeComponent();

            if (!VirtualizationManager.IsInitialized) {
                //set the VirtualizationManager’s UIThreadExcecuteAction. In this case
                //we’re using Dispatcher.Invoke to give the VirtualizationManager access
                //to the dispatcher thread, and using a DispatcherTimer to run the background
                //operations the VirtualizationManager needs to run to reclaim pages and manage memory.
                VirtualizationManager.Instance.UIThreadExcecuteAction =
                    (a) => Dispatcher.Invoke(a);
                        new DispatcherTimer(
                            TimeSpan.FromSeconds(1),
                            DispatcherPriority.Background,
                            delegate(object s, EventArgs a)
                            {
                                VirtualizationManager.Instance.ProcessActions();
                            },
                            this.Dispatcher).Start();
            }
        }

        private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) {
            _myDataVirtualized = new VirtualizingObservableCollection<Customer>(
                        new PaginationManager<Customer>(new Provider(), maxPages: 1, pageSize: 50));

            this.TheDataGrid.AutoGenerateColumns = false;

            DataGridTextColumn col1 = new DataGridTextColumn();
            col1.Header = "Random";
            col1.Binding = new Binding("ID");
            TheDataGrid.Columns.Add(col1);

            DataGridTextColumn col2 = new DataGridTextColumn();
            col2.Header = "Name";
            col2.Binding = new Binding("Name");

            col2.SortDirection = ListSortDirection.Ascending;

            TheDataGrid.Columns.Add(col2);

            DataGridTextColumn col3 = new DataGridTextColumn();
            col3.Header = "Address";
            col3.Binding = new Binding("Address");
            TheDataGrid.Columns.Add(col3);

            // note causes the DataGrid to immediately load all items
            //this.TheDataGrid.Items.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));

            this.TheDataGrid.ItemsSource = _myDataVirtualized;
        }

        /// <summary>
        /// Refresh
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click(object sender, RoutedEventArgs e) {
            //_myDataVirtualized.ResetAsync();
            //this.TheDataGrid.Items.Refresh();
            _myDataVirtualized.Clear();
        }

        private void TheDataGrid_OnSorting(object sender, DataGridSortingEventArgs e) {
            //Dispatcher.BeginInvoke((Action)(()=>
            //{
            //    // call .Clear() on the virtualizingObservableCollection to force a refresh / reset
            //    _myDataVirtualized.Clear();
            //}));

            _myDataVirtualized.Clear();
            e.Handled = true;

        }

        private void ButtonChangeItem_Click(object sender, RoutedEventArgs e) {
            if (TheDataGrid.SelectedItem != null) {
                var customer = (Customer) this.TheDataGrid.SelectedItem;
                // notify all changes
                customer.SendPropsChanged();
            }
        }
    }

    public class Provider : IPagedSourceProvider<Customer> {

        public int Count {
            get { return 5000; }
        }

        public PagedSourceItemsPacket<Customer> GetItemsAt(int pageoffset, int count, bool usePlaceholder) {

            try {
                Mouse.OverrideCursor = Cursors.Wait;

                Debug.WriteLine("Fetching items offset {0}, count {1}", pageoffset, count);

                PagedSourceItemsPacket<Customer> result = new PagedSourceItemsPacket<Customer>();

                List<Customer> list = new List<Customer>();
                for (int n = 0; n < count; ++n) {
                    list.Add(new Customer() { Index = pageoffset + n, Name = "Customer " + (pageoffset + n).ToString(), Address = "Address " + (pageoffset + n).ToString() });
                }

                result.LoadedAt = DateTime.Now;
                result.Items = list;

                Thread.Sleep(100);

                return result;

            } finally {
                Mouse.OverrideCursor = Cursors.Arrow;
            }
        }

        public int IndexOf(Customer item) {
            return item.Index;
        }

        public void OnReset(int count) {

        }
    }

    public class Customer : INotifyPropertyChanged {

        private static Random rnd = new Random();

        // random id to see effect of Items.Refresh()
        public int ID { get { return rnd.Next(1000); } }
        public string Name { get; set; }
        public string Address { get; set; }
        public int Index { get; set; }

        public void SendPropsChanged() {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(string.Empty));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
anagram4wander commented 9 years ago

Try the resetasync rather than the clear method..

Sent from my iPhone

On Sep 10, 2015, at 3:20 AM, bjvanhaaff notifications@github.com wrote:

I already do that, but it was not the cause anyway. In the code a default sort order was set using TheDataGrid.Items.SortDescriptions.Add(...). this causes the grid to access all items as soon as ItemsSource is set. Initial loading is solved now but i still have an issue with refreshing/sorting. When calling VirtualizingObservableCollection.Clear() (like in your example), the first time it works okay but the second time this method is invoked, all items are being retrieved. I can send you a small program to demonstrate this if needed (main code is below). My real data originates from a EF based datasource and I'm using Take() and Skip() to fetch the right data form a sorted/filtered dataset. It's also not clear to me how to implement IndexOf() with EF and I guess I need this to keep the selected row in the DataGrid when the data is refreshed.

Thank you for your assistance.

using AlphaChiTech.Virtualization; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input;

using System.Windows.Threading;

namespace VirtualizingObservableCollection {

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {

    private VirtualizingObservableCollection<Customer> _myDataVirtualized = null;

    public MainWindow() {
        InitializeComponent();

        if (!VirtualizationManager.IsInitialized) {
            //set the VirtualizationManager’s UIThreadExcecuteAction. In this case
            //we’re using Dispatcher.Invoke to give the VirtualizationManager access
            //to the dispatcher thread, and using a DispatcherTimer to run the background
            //operations the VirtualizationManager needs to run to reclaim pages and manage memory.
            VirtualizationManager.Instance.UIThreadExcecuteAction =
                (a) => Dispatcher.Invoke(a);
                    new DispatcherTimer(
                        TimeSpan.FromSeconds(1),
                        DispatcherPriority.Background,
                        delegate(object s, EventArgs a)
                        {
                            VirtualizationManager.Instance.ProcessActions();
                        },
                        this.Dispatcher).Start();
        }
    }

    private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) {
        _myDataVirtualized = new VirtualizingObservableCollection<Customer>(
                    new PaginationManager<Customer>(new Provider(), maxPages: 1, pageSize: 50));

        this.TheDataGrid.AutoGenerateColumns = false;

        DataGridTextColumn col1 = new DataGridTextColumn();
        col1.Header = "Random";
        col1.Binding = new Binding("ID");
        TheDataGrid.Columns.Add(col1);

        DataGridTextColumn col2 = new DataGridTextColumn();
        col2.Header = "Name";
        col2.Binding = new Binding("Name");

        col2.SortDirection = ListSortDirection.Ascending;

        TheDataGrid.Columns.Add(col2);

        DataGridTextColumn col3 = new DataGridTextColumn();
        col3.Header = "Address";
        col3.Binding = new Binding("Address");
        TheDataGrid.Columns.Add(col3);

        // note causes the DataGrid to immediately load all items
        //this.TheDataGrid.Items.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));

        this.TheDataGrid.ItemsSource = _myDataVirtualized;
    }

    /// <summary>
    /// Refresh
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button_Click(object sender, RoutedEventArgs e) {
        //_myDataVirtualized.ResetAsync();
        //this.TheDataGrid.Items.Refresh();
        _myDataVirtualized.Clear();
    }

    private void TheDataGrid_OnSorting(object sender, DataGridSortingEventArgs e) {
        //Dispatcher.BeginInvoke((Action)(()=>
        //{
        //    // call .Clear() on the virtualizingObservableCollection to force a refresh / reset
        //    _myDataVirtualized.Clear();
        //}));

        _myDataVirtualized.Clear();
        e.Handled = true;

    }

    private void ButtonChangeItem_Click(object sender, RoutedEventArgs e) {
        if (TheDataGrid.SelectedItem != null) {
            var customer = (Customer) this.TheDataGrid.SelectedItem;
            // notify all changes
            customer.SendPropsChanged();
        }
    }
}

public class Provider : IPagedSourceProvider<Customer> {

    public int Count {
        get { return 5000; }
    }

    public PagedSourceItemsPacket<Customer> GetItemsAt(int pageoffset, int count, bool usePlaceholder) {

        try {
            Mouse.OverrideCursor = Cursors.Wait;

            Debug.WriteLine("Fetching items offset {0}, count {1}", pageoffset, count);

            PagedSourceItemsPacket<Customer> result = new PagedSourceItemsPacket<Customer>();

            List<Customer> list = new List<Customer>();
            for (int n = 0; n < count; ++n) {
                list.Add(new Customer() { Index = pageoffset + n, Name = "Customer " + (pageoffset + n).ToString(), Address = "Address " + (pageoffset + n).ToString() });
            }

            result.LoadedAt = DateTime.Now;
            result.Items = list;

            Thread.Sleep(100);

            return result;

        } finally {
            Mouse.OverrideCursor = Cursors.Arrow;
        }
    }

    public int IndexOf(Customer item) {
        return item.Index;
    }

    public void OnReset(int count) {

    }
}

public class Customer : INotifyPropertyChanged {

    private static Random rnd = new Random();

    // random id to see effect of Items.Refresh()
    public int ID { get { return rnd.Next(1000); } }
    public string Name { get; set; }
    public string Address { get; set; }
    public int Index { get; set; }

    public void SendPropsChanged() {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(string.Empty));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

} — Reply to this email directly or view it on GitHub.

anagram4wander commented 9 years ago

Ah.. Now I see the problem, sort does cause a reload of everything.. To sort it..

Not sure how to work around that one - let me mull on it..

Sent from my iPhone

On Sep 10, 2015, at 3:20 AM, bjvanhaaff notifications@github.com wrote:

I already do that, but it was not the cause anyway. In the code a default sort order was set using TheDataGrid.Items.SortDescriptions.Add(...). this causes the grid to access all items as soon as ItemsSource is set. Initial loading is solved now but i still have an issue with refreshing/sorting. When calling VirtualizingObservableCollection.Clear() (like in your example), the first time it works okay but the second time this method is invoked, all items are being retrieved. I can send you a small program to demonstrate this if needed (main code is below). My real data originates from a EF based datasource and I'm using Take() and Skip() to fetch the right data form a sorted/filtered dataset. It's also not clear to me how to implement IndexOf() with EF and I guess I need this to keep the selected row in the DataGrid when the data is refreshed.

Thank you for your assistance.

using AlphaChiTech.Virtualization; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input;

using System.Windows.Threading;

namespace VirtualizingObservableCollection {

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {

    private VirtualizingObservableCollection<Customer> _myDataVirtualized = null;

    public MainWindow() {
        InitializeComponent();

        if (!VirtualizationManager.IsInitialized) {
            //set the VirtualizationManager’s UIThreadExcecuteAction. In this case
            //we’re using Dispatcher.Invoke to give the VirtualizationManager access
            //to the dispatcher thread, and using a DispatcherTimer to run the background
            //operations the VirtualizationManager needs to run to reclaim pages and manage memory.
            VirtualizationManager.Instance.UIThreadExcecuteAction =
                (a) => Dispatcher.Invoke(a);
                    new DispatcherTimer(
                        TimeSpan.FromSeconds(1),
                        DispatcherPriority.Background,
                        delegate(object s, EventArgs a)
                        {
                            VirtualizationManager.Instance.ProcessActions();
                        },
                        this.Dispatcher).Start();
        }
    }

    private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) {
        _myDataVirtualized = new VirtualizingObservableCollection<Customer>(
                    new PaginationManager<Customer>(new Provider(), maxPages: 1, pageSize: 50));

        this.TheDataGrid.AutoGenerateColumns = false;

        DataGridTextColumn col1 = new DataGridTextColumn();
        col1.Header = "Random";
        col1.Binding = new Binding("ID");
        TheDataGrid.Columns.Add(col1);

        DataGridTextColumn col2 = new DataGridTextColumn();
        col2.Header = "Name";
        col2.Binding = new Binding("Name");

        col2.SortDirection = ListSortDirection.Ascending;

        TheDataGrid.Columns.Add(col2);

        DataGridTextColumn col3 = new DataGridTextColumn();
        col3.Header = "Address";
        col3.Binding = new Binding("Address");
        TheDataGrid.Columns.Add(col3);

        // note causes the DataGrid to immediately load all items
        //this.TheDataGrid.Items.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));

        this.TheDataGrid.ItemsSource = _myDataVirtualized;
    }

    /// <summary>
    /// Refresh
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button_Click(object sender, RoutedEventArgs e) {
        //_myDataVirtualized.ResetAsync();
        //this.TheDataGrid.Items.Refresh();
        _myDataVirtualized.Clear();
    }

    private void TheDataGrid_OnSorting(object sender, DataGridSortingEventArgs e) {
        //Dispatcher.BeginInvoke((Action)(()=>
        //{
        //    // call .Clear() on the virtualizingObservableCollection to force a refresh / reset
        //    _myDataVirtualized.Clear();
        //}));

        _myDataVirtualized.Clear();
        e.Handled = true;

    }

    private void ButtonChangeItem_Click(object sender, RoutedEventArgs e) {
        if (TheDataGrid.SelectedItem != null) {
            var customer = (Customer) this.TheDataGrid.SelectedItem;
            // notify all changes
            customer.SendPropsChanged();
        }
    }
}

public class Provider : IPagedSourceProvider<Customer> {

    public int Count {
        get { return 5000; }
    }

    public PagedSourceItemsPacket<Customer> GetItemsAt(int pageoffset, int count, bool usePlaceholder) {

        try {
            Mouse.OverrideCursor = Cursors.Wait;

            Debug.WriteLine("Fetching items offset {0}, count {1}", pageoffset, count);

            PagedSourceItemsPacket<Customer> result = new PagedSourceItemsPacket<Customer>();

            List<Customer> list = new List<Customer>();
            for (int n = 0; n < count; ++n) {
                list.Add(new Customer() { Index = pageoffset + n, Name = "Customer " + (pageoffset + n).ToString(), Address = "Address " + (pageoffset + n).ToString() });
            }

            result.LoadedAt = DateTime.Now;
            result.Items = list;

            Thread.Sleep(100);

            return result;

        } finally {
            Mouse.OverrideCursor = Cursors.Arrow;
        }
    }

    public int IndexOf(Customer item) {
        return item.Index;
    }

    public void OnReset(int count) {

    }
}

public class Customer : INotifyPropertyChanged {

    private static Random rnd = new Random();

    // random id to see effect of Items.Refresh()
    public int ID { get { return rnd.Next(1000); } }
    public string Name { get; set; }
    public string Address { get; set; }
    public int Index { get; set; }

    public void SendPropsChanged() {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(string.Empty));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

} — Reply to this email directly or view it on GitHub.