Inconsistent aggregate calculations when paging a gridview

4 posts, 0 answers
  1. Scott
    Scott avatar
    14 posts
    Member since:
    Mar 2013

    Posted 21 Oct 2013 Link to this post

    I've got an otherwise working RadGridView being successfully paged (client-side) with the RadDataPager. I'm unclear what the expected behavior for a column aggregate function should be in this scenario, but what I'm getting has me a little stumped.

    When the grid initially loads, the result of the CountFunction gives me the number of items on the current page, 10 in my current setup. Once I advance to the next page, the total is updated to reflect the count of the entire collection, in this case 100. At that point, I can change pages all day and it continues to show the full amount (100).

    Is this the expected behavior or have I messed something up. I assume it has to do with the collection being enumerated differently on page change than when initially loaded. I'd actually prefer it gave me counts/sums from the entire collection rather than just the current page, but right now I'd just be happy with it consistently doing one or the other.

    Any insight would be appreciated. I know I can just use a regular footer and calculate the values on my own, but it feels like the aggregates are almost trying to do what I want, so figured I'd run that down first.

    Thank you.

  2. Nick
    Admin
    Nick avatar
    593 posts

    Posted 24 Oct 2013 Link to this post

    Hi Scott,

    Unfortunately we are not able to determine what goes wrong by the information from your post. 

    May I ask you to send a sample that reproduces the problem so we can debug it on our side and see where the issue resides?

    Thank you in advance! 

    Regards,
    Nik
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for SILVERLIGHT.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  3. DevCraft banner
  4. Scott
    Scott avatar
    14 posts
    Member since:
    Mar 2013

    Posted 24 Oct 2013 Link to this post


    I've made some progress isolating the issue over the last few days.

    By themselves, the grid and pager behaved as expected, correctly reporting aggregates on load rather than after page change. I couldn't reproduce the issue in my test project until I added in the Caliburn and Reactive Extensions code from my main application.

    The viewmodel and xaml below are pretty basic, but the ThrottledWorker usage in the viewmodel is a pretty good indicator of how the main application is pulling data from our service and populating the bound collection. The strange behavior with the paging/aggregates comes from the following line in ThrottledWorker.cs.

    this._startObservable
        .Throttle(TimeSpan.FromMilliseconds(100), DispatcherScheduler.Current)
        .Subscribe(_ => this.StartWork());

    Commenting out the .Throttle(...) line causes the issue to go away, but pretty majorly breaks the rest of my app. I can make a special case for this one view and move on for now, but am curious to know why the throttling feature interacts with the paging/grid/aggregates/etc... the way it does so I can avoid it better in the future.

    I appreciate any insight you may have. The rest of the code from the my sample project follows.

    Thank you.

    MainPageViewModel.cs
    public class MainPageViewModel : Screen
        {
            public MainPageViewModel()
            {
                this.Data = new ObservableCollection<TestObject>();
                this.Worker = new ThrottledWorker(this.LoadData);
            }
     
            public ObservableCollection<TestObject> Data { get; set; }
            public ThrottledWorker Worker { get; set; }
     
            protected override void OnInitialize()
            {
                this.Worker.Start();
                base.OnInitialize();
            }
     
            public IEnumerable<IResult> LoadData()
            {
                var operation = new TestOperation(100);
                yield return operation;
                foreach (var item in operation.Result)
                {
                    this.Data.Add(item);
                }
            }
        }

    ThrottledWorker.cs
    public class ThrottledWorker : PropertyChangedBase
        {
            public ThrottledWorker(Func<IEnumerable<IResult>> routine)
            {
                this._routine = routine;
                this._startObservable
                    .Throttle(TimeSpan.FromMilliseconds(100), DispatcherScheduler.Current)
                    .Subscribe(_ => this.StartWork());
            }
     
            private readonly Func<IEnumerable<IResult>> _routine;
            private readonly Subject<Unit> _startObservable = new Subject<Unit>();
            private bool _isWorking;
     
            public virtual void Start()
            {
                this._startObservable.OnNext(Unit.Default);
            }
     
            public bool IsBusy { get; set; }
            public bool WorkQueued { get; set; }
     
            private void StartWork()
            {
                if (!this._isWorking)
                {
                    this.DoWork();
                }
                else
                {
                    this.WorkQueued = true;
                }
            }
     
            protected virtual IResult CreateEnumerator()
            {
                return Coroutine.CreateParentEnumerator(this._routine().GetEnumerator());
            }
     
            private void DoWork()
            {
                this.IsBusy = true;
                this._isWorking = true;
                var enumerator = this.CreateEnumerator();
                enumerator.Completed += this.enumerator_Completed;
                enumerator.Execute(new ActionExecutionContext());
            }
     
            private void enumerator_Completed(object sender, ResultCompletionEventArgs e)
            {
                this._isWorking = false;
                if (this.WorkQueued)
                {
                    this.WorkQueued = false;
                    this.DoWork();
                }
                else
                {
                    this.IsBusy = false;
                }
            }
        }


    MainPage.xaml

    <UserControl x:Class="RadControlsSilverlightApp1.MainPage"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
                 mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
     
        <Grid x:Name="LayoutRoot">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
     
            <telerik:RadGridView Grid.Row="0"
                                 ItemsSource="{Binding PagedSource, ElementName=MyDataPager}"
                                 ShowColumnFooters="True"
                                 AutoGenerateColumns="False">
                <telerik:RadGridView.Columns>
                    <telerik:GridViewDataColumn Header="ID"
                                                DataMemberBinding="{Binding Id}"
                                                Width="1*" />
                    <telerik:GridViewDataColumn Header="Name"
                                                DataMemberBinding="{Binding Name}"
                                                Width="6*">
                        <telerik:GridViewDataColumn.AggregateFunctions>
                            <telerik:CountFunction Caption="Count: " />
                        </telerik:GridViewDataColumn.AggregateFunctions>
                    </telerik:GridViewDataColumn>
                    <telerik:GridViewDataColumn Header="Value"
                                                DataMemberBinding="{Binding Value}"
                                                Width="3*">
                        <telerik:GridViewDataColumn.AggregateFunctions>
                            <telerik:SumFunction />
                        </telerik:GridViewDataColumn.AggregateFunctions>
                    </telerik:GridViewDataColumn>
                </telerik:RadGridView.Columns>
            </telerik:RadGridView>
     
            <telerik:RadDataPager Grid.Row="1"
                                  x:Name="MyDataPager"
                                  IsTotalItemCountFixed="True"
                                  Source="{Binding Data}"
                                  AutoEllipsisMode="Both"
                                  DisplayMode="All"
                                  PageSize="10" />
        </Grid>
    </UserControl>

    TestOperation.cs
    public class TestOperation : IResult
        {
            public TestOperation(int count)
            {
                this.Count = count;
            }
     
            public int Count { get; set; }
            public IList<TestObject> Result { get; set; }
     
            #region IResult Members
     
            public event EventHandler<ResultCompletionEventArgs> Completed;
     
            public void Execute(ActionExecutionContext context)
            {
                this.Result = CreateTestData(this.Count);
                if (this.Completed != null)
                {
                    Caliburn.Micro.Execute.OnUIThread(() =>
                        this.Completed(this, new ResultCompletionEventArgs()));
                }
            }
     
            #endregion
     
            private static IList<TestObject> CreateTestData(int count)
            {
                var list = new List<TestObject>(count);
     
                for (var i = 0; i < count; i++)
                {
                    list.Add(new TestObject
                    {
                        Id = i,
                        Name = "Test Item " + i,
                        Value = i
                    });
                }
     
                return list;
            }
        }
     
        public class TestObject
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Value { get; set; }
        }

  5. Nick
    Admin
    Nick avatar
    593 posts

    Posted 29 Oct 2013 Link to this post

    Hello Scott,

    I suspect this has to do with the fact that when the Pager firstly initiates the Throttle method has not finished returning items leading to Pager showing smaller amount of pages than there actually are. 

    Unfortunately, there isn't much we can do, other than suggesting some kind of an alternative approach, or trying to update the Pager runtime while the ThrottleWorker does its job.

    Hope this makes sense! 

    Regards,
    Nik
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for SILVERLIGHT.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
Back to Top