This is a migrated thread and some comments may be shown as answers.

CalculateAggregates doesn't work

15 Answers 228 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Konrad Sikorski
Top achievements
Rank 1
Konrad Sikorski asked on 17 Jun 2011, 01:40 PM
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
    }
}

15 Answers, 1 is accepted

Sort by
0
Dimitrina
Telerik team
answered on 21 Jun 2011, 10:11 AM
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
0
Michael
Top achievements
Rank 1
answered on 25 Jan 2013, 02:50 AM
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)
0
Dimitrina
Telerik team
answered on 25 Jan 2013, 11:54 AM
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.

0
Michael
Top achievements
Rank 1
answered on 28 Jan 2013, 10:16 PM
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 ...)
0
Myles
Top achievements
Rank 1
answered on 02 Sep 2013, 12:33 PM
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?
0
Dimitrina
Telerik team
answered on 02 Sep 2013, 02:05 PM
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 >>
0
Myles
Top achievements
Rank 1
answered on 03 Sep 2013, 07:59 AM

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?

0
Dimitrina
Telerik team
answered on 03 Sep 2013, 12:24 PM
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 >>
0
Myles
Top achievements
Rank 1
answered on 03 Sep 2013, 02:25 PM
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).
0
Dimitrina
Telerik team
answered on 04 Sep 2013, 07:56 AM
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 >>
0
Myles
Top achievements
Rank 1
answered on 04 Sep 2013, 08:16 AM
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.
0
Dimitrina
Telerik team
answered on 04 Sep 2013, 08:39 AM
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 >>
0
Myles
Top achievements
Rank 1
answered on 04 Sep 2013, 09:02 AM
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.
0
Dimitrina
Telerik team
answered on 06 Sep 2013, 08:13 AM
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 >>
0
Brandon
Top achievements
Rank 1
answered on 15 Dec 2017, 04:45 PM

If I understand this post correctly, doing a rebind on the grid would solve the issue? Leaving this here in case it's useful for someone else.

<code>ucGrid.rebind();</code>

Tags
GridView
Asked by
Konrad Sikorski
Top achievements
Rank 1
Answers by
Dimitrina
Telerik team
Michael
Top achievements
Rank 1
Myles
Top achievements
Rank 1
Brandon
Top achievements
Rank 1
Share this question
or