CalculateAggregates doesn't work

15 posts, 0 answers
  1. Konrad Sikorski
    Konrad Sikorski avatar
    23 posts
    Member since:
    Jul 2010

    Posted 17 Jun 2011 Link to this post

    I have simple grid with grouping and simple aggregation. When I want to update entries value (from code) than grid will update entries correctly but aggregation value is not updated. Calling CalculateAgreggates has no effects.
    <UserControl x:Class="tmpTelerikGridAggregationBug.MainPage"
        xmlns:Controls="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.GridView"
                 xmlns:Data="clr-namespace:Telerik.Windows.Data;assembly=Telerik.Windows.Data" Height="300" Width="400">
      
        <StackPanel>
            <Controls:RadGridView x:Name="ucGrid" AutoExpandGroups="True" AutoGenerateColumns="False" >
                <Controls:RadGridView.Columns>
                    <Controls:GridViewDataColumn UniqueName="Name" />
                    <Controls:GridViewDataColumn UniqueName="Age" >
      
                        <Controls:GridViewDataColumn.AggregateFunctions>
                            <Data:SumFunction SourceField="Age" />
                        </Controls:GridViewDataColumn.AggregateFunctions>
                          
                    </Controls:GridViewDataColumn>
                    <Controls:GridViewDataColumn UniqueName="Group" />
                </Controls:RadGridView.Columns>
            </Controls:RadGridView>
                <Button x:Name="ucButton" Click="ucButton_Click" Content="0"/>
        </StackPanel>
    </UserControl>
    namespace tmpTelerikGridAggregationBug 
    {
        public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
      
                var groupDescriptor = new ColumnGroupDescriptor { Column = this.ucGrid.Columns["Group"] };
                this.ucGrid.GroupDescriptors.Add( groupDescriptor );
      
                ucGrid.ItemsSource = new ObservableCollection<Person>
                              {
                                  new Person{Name="N1", Age=1, Group="G1"},
                                  new Person{Name="N2", Age=2, Group="G1"},
                                  new Person{Name="N3", Age=3, Group="G2"},
                                  new Person{Name="N4", Age=4, Group="G2"},
                              };
            }
      
            private void ucButton_Click( object sender, RoutedEventArgs e )
            {
                int newValue = new Random().Next( 9 ) + 1;
                ucButton.Content = newValue;
      
                UpdateData( newValue );
            }
      
            private void UpdateData(int value)
            {
                foreach( var person in ucGrid.Items.Cast<Person>() )
                {
                    person.Age += value;
                }
      
                ucGrid.CalculateAggregates(); 
            }
        }
      
        public class Person : INotifyPropertyChanged
        {
            private int _age;
      
            [Required]
            public string Group { get; set; }
            public string Name { get; set; }
            public int Age
            {
                get { return _age; }
                set
                {
                    _age = value;
                    OnPropertyChanged( "Age" );
                }
            }
      
            #region Implementation of INotifyPropertyChanged
      
            public event PropertyChangedEventHandler PropertyChanged;
      
            protected void OnPropertyChanged( string name )
            {
                var handler = PropertyChanged;
                if( handler != null )
                {
                    handler( this, new PropertyChangedEventArgs( name ) );
                }
            }
      
            #endregion
        }
    }
  2. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 21 Jun 2011 Link to this post

    Hello Konrad Sikorski,

     You are right, the aggregate functions in the group footer are not recalculated by the CalculateAggregates() method. This is due to the fact that the group footers will be updated when the collection changes. When you change the person.Age value only the property changed is raised.
    What you should use so that the group footers are calculated is to inform the GridView  that the Collection has been changed, like so:

    private void UpdateData(int value)
    {
    var items = ucGrid.Items.Cast<Person>().ToList();
     
    for (int i = 0; i < ucGrid.Items.Count; i++)
    {
    var person = items[i];
    if (person != null)
    {
     ((IEditableCollectionView)this.clubsGrid.Items).EditItem(person);
    person.Age += value;
    ((IEditableCollectionView)this.clubsGrid.Items).CommitEdit();
    }
    }
    }

    This way when the editing is done on the data level, the group aggregate footer will be updated accordingly.

    Greetings,
    Didie
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  3. DevCraft banner
  4. Michael
    Michael avatar
    3 posts
    Member since:
    Jan 2013

    Posted 24 Jan 2013 Link to this post

    Sorry for reviving this thread, but is there a simpler way to implement this ?

    We currently have an observable collection, and we run the aggregate on a particular property.
    This observable collection is updated via external REST calls to a server. In order to optimise performance, rather than blow away the observable and recreate it, we update the idividual items in the list (via a synchronisation method), and add/remove new or deleted items.

    To do this via an EditItem/CommitEdit will make the code wildly and unmaintainable (and unusable outside of the gridview).

    Are there any suggestions ?

    I am currently trying out the RadControls_for_Silverlight4_2012_2_0912_DEV_hotfix .

    (FWIW, adding/removing items does trigger an aggregate recalculation)
  5. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 25 Jan 2013 Link to this post

    Hello,

    The aggregates will be updated when a CollectionChanged event is raised from the bound ItemsSource. If you can raise such a notification not using the EditItem/CommitEdit methods, then this will work for you.

    Regards,
    Didie
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  6. Michael
    Michael avatar
    3 posts
    Member since:
    Jan 2013

    Posted 28 Jan 2013 Link to this post

    Thanks for the reply.
    I did try doing the "remove old item, insert updated item" thing. Which worked, but was very unperformant. I did read up on performance issues when the grid size resolves to infinity, but I also had performance problems when I gave the grid a static size.
    Are there any other issues I should know about performance wise ?

    I've gone over the performance considerations, and beleive they are all addressed (there is one complex binding, so I'll have a quick go at simplifiying that one ...)
  7. Myles
    Myles avatar
    13 posts
    Member since:
    May 2012

    Posted 02 Sep 2013 Link to this post

    Sorry to resurrect this thread yet again but I have the same problem as the original poster, and have tried using CollectionChanged as suggested.  I am removing a stale item out of a ObservableCollection and then replacing it with a new updated version.  The CollectionChanged event on the ObservableCollection gets fired within the ViewModel but yet the aggregates in my Telerik grid group headers still do not get updated.

    Your first solution of iterating over the grid and executing EditItem and CommitEdit on all items is a very poor solution.  Try doing this on a grid with over 500 rows. 

    There must be a better solution to this problem?
  8. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 02 Sep 2013 Link to this post

    Hi,

    The aggregates should be updated once a Reset action is raised for the bound source collection. May I ask you to please confirm if you test with the latest version? 
     

    Regards,
    Didie
    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 >>
  9. Myles
    Myles avatar
    13 posts
    Member since:
    May 2012

    Posted 03 Sep 2013 Link to this post

    I have the latest version of the Silverlight grid control (2013.2.724.1050).  What do you mean by "Reset" action?  Do you have a code example?

  10. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 03 Sep 2013 Link to this post

    Hello,

    If you set the collection to null and then assign a value to it, a CollectionChanged with NotifyCollectionChangedAction.Reset will be raised. The other actions should also refresh the aggregate values. I have tested removing or/and adding an item in a ObservableCollection. The aggregates are properly updated once a CollectionChanged event is raised. 

    Would it be possible for you to isolate the problem in a demo project and send it to us?

    Regards,
    Didie
    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 >>
  11. Myles
    Myles avatar
    13 posts
    Member since:
    May 2012

    Posted 03 Sep 2013 Link to this post

    As I previously said, my ViewModel is already raising a CollectionChanged event but the column footer aggregates are not updating (see screen shot).

    In an attempt to get the column footer aggregates to update, I am removing and adding an item from the bound ObservableCollection after a line item is updated  e.g: (snippet of ViewModel code)

    var clone = SerializeHelper.CloneObject(updateddataobject);
    BoundObservableCollection.Remove(updateddataobject);
    BoundObservableCollection.Insert(0,clone);


    I can confirm that this raises the CollectionChanged event on BoundObservableCollection property
    (this is the ObservableCollection that is bound to the grid ItemsSource).
  12. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 04 Sep 2013 Link to this post

    Hi,

    I have attached a test project showing my attempt to reproduce a problem with recalculating the aggregates.

    Would you please check it and let me know how is it different from your solution?

    Regards,
    Didie
    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 >>
  13. Myles
    Myles avatar
    13 posts
    Member since:
    May 2012

    Posted 04 Sep 2013 Link to this post

    The difference is that your grid is not displaying inline aggregates.  It is the inline aggregates (see my previous screen shot) that I am having the problem with.  I could resolve this issue by simply turning the inline aggregates off, but as explained in a related thread (http://www.telerik.com/community/forums/silverlight/gridview/gridview-aggregates-issue.aspx) , I am unable to do this without using the default Telerik theme for the grid.
  14. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 04 Sep 2013 Link to this post

    Hi,

    I added inline aggregates and after I changed an item from the GridView, I got them updated. Would you please let me know what exactly should I change in the attached test project so that I can reproduce the issue?

    Regards,
    Didie
    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 >>
  15. Myles
    Myles avatar
    13 posts
    Member since:
    May 2012

    Posted 04 Sep 2013 Link to this post

    OK I can now replicate the bug in your sample code.  Change your data in Club.cs as follows:

            public static ObservableCollection<Club> GetClubs()
            {
                ObservableCollection<Club> clubs = new ObservableCollection<Club>();
                Club club;
     
                // Liverpool
                club = new Club("Liverpool"new DateTime(1892, 1, 1), 76212);
                club.Players.Add(new Player("Pepe Reina", 25, Position.GK, "Spain"));
                club.Players.Add(new Player("Jamie Carragher", 23, Position.DF, "England"));
                club.Players.Add(new Player("Steven Gerrard", 8, Position.MF, "England"));
                club.Players.Add(new Player("Fernando Torres", 9, Position.FW, "Spain"));
                clubs.Add(club);
     
                // Manchester Utd.
                club = new Club("Manchester Utd."new DateTime(1878, 1, 1), 76212);
                club.Players.Add(new Player("Edwin van der Sar", 1, Position.GK, "Netherlands"));
                club.Players.Add(new Player("Rio Ferdinand", 5, Position.DF, "England"));
                club.Players.Add(new Player("Ryan Giggs", 11, Position.MF, "Wales"));
                club.Players.Add(new Player("Wayne Rooney", 10, Position.FW, "England"));
                clubs.Add(club);
     
                // Chelsea
                club = new Club("Liverpool"new DateTime(1905, 1, 1), 42055);
                club.Players.Add(new Player("Petr Čech", 1, Position.GK, "Czech Republic"));
                club.Players.Add(new Player("John Terry", 26, Position.DF, "England"));
                club.Players.Add(new Player("Frank Lampard", 8, Position.MF, "England"));
                club.Players.Add(new Player("Nicolas Anelka", 39, Position.FW, "France"));
                clubs.Add(club);
     
                // Arsenal
                club = new Club("Arsenal"new DateTime(1886, 1, 1), 60355);
                club.Players.Add(new Player("Manuel Almunia", 1, Position.GK, "Spain"));
                club.Players.Add(new Player("Gaël Clichy", 22, Position.DF, "France"));
                club.Players.Add(new Player("Cesc Fàbregas", 4, Position.MF, "Spain"));
                club.Players.Add(new Player("Robin van Persie", 11, Position.FW, "Netherlands"));
                clubs.Add(club);
     
                return clubs;
            }

    There are now two Liverpool clubs.  Run the test program and group by Name.  You should see two records under the Liverpool grouping with a sum stadium capacity of 118267.  Now click the "Update Value on first item" button.  The first Liverpool record has the statium capacity changed to 39, however, the column aggregate still states that the sum is 118267.  It has not been updated correctly.  Please confirm whether you see the same behavior.
  16. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 06 Sep 2013 Link to this post

    Hello,

    We were able to reproduce the issue.
     
    You will need to first remove the item, then edit it and at the end insert it back to the collection:

    private void Button1_Click(object sender, RoutedEventArgs e)
    {
        var collection = this.clubsGrid.ItemsSource as ObservableCollection<Club>;
     
        var firstItem = collection[0] as Club;
        collection.Remove(firstItem);
     
        firstItem.StadiumCapacity = 39;

        collection.Insert(0, firstItem);
    }

    If you follow this pattern, then the value will be updated fine.
     

    Regards,
    Didie
    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
DevCraft banner