Question send Sum of collectionview field to an other field

Supermack

Member
Joined
Feb 4, 2023
Messages
9
Programming Experience
Beginner
Hello,

i need to group lists in a collectionview then to send the sum of all fields (Individual_Note) of the nested List into a field (Total_Note) in the CollectionView.GroupHeader.
This, every time the the value of Individual_Note changed.

Thanks for your advices.


C#:
 <CollectionView x:Name="cv1" ItemsSource="{Binding MainList}" IsGrouped="True">
                <CollectionView.GroupHeaderTemplate >
                        <DataTemplate x:DataType="model:NestedList" >
                            <HorizontalStackLayout Spacing="15" HorizontalOptions="Center" Padding="5" BackgroundColor="LightGray">
                               <Label Text="{Binding Name}" BackgroundColor="LightGray" FontSize="18" FontAttributes="Bold" />
                                   <alohakit:Rating IsReadOnly="True"  Value="{Binding Total_Note, Mode=TwoWay}" Grid.Row="1" BackgroundColor="Green" UnSelectedFill="Beige" SelectedFill="ForestGreen" SelectedStroke="Azure" />
                                </HorizontalStackLayout>
                        </DataTemplate>
                </CollectionView.GroupHeaderTemplate>
                <CollectionView.ItemTemplate>
                        <DataTemplate x:DataType="model:UserShort">
                            <Frame CornerRadius="15" Padding="10" Margin="0,2,0,2" BackgroundColor="White">
                                <Grid ColumnSpacing="1" RowSpacing="5" ColumnDefinitions="Auto, *" RowDefinitions="*,*">
                                <Grid RowSpacing="2" RowDefinitions="Auto,Auto" >
                                    <toolkit:AvatarView ImageSource="{Binding Photo}" HorizontalOptions="Start"/>
                                        <Label Text="{Binding Alias}" Grid.Row="1" HorizontalOptions="Center" FontFamily="Metropolis Regular" FontSize="12" />
                                </Grid>

                                    <Grid Grid.Column="1" Grid.RowSpan="2" HorizontalOptions="Center" VerticalOptions="Center" >
                                        <alohakit:Rating Value="{Binding Individual_Note, Mode=TwoWay}" Grid.Row="1" HorizontalOptions="End" BackgroundColor="Green" UnSelectedFill="Beige" SelectedFill="ForestGreen" SelectedStroke="Azure"/>                                    
                                    </Grid>
                            </Grid>

                        </Frame>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
 
Perhaps I'm missing something. Isn't your Total_Note bound to your view model? Just update the value of Total_Note with the sum of MainList's Individual_Note values. Something like:
C#:
Total_Note = MainList.Sum(n => n.Individual_Note);
 
Perhaps I'm missing something. Isn't your Total_Note bound to your view model? Just update the value of Total_Note with the sum of MainList's Individual_Note values. Something like:
C#:
Total_Note = MainList.Sum(n => n.Individual_Note);

Hello,
Total_Note must be unique for each nested lists (NestedList)
Maybe with this example, it will be more explicit:

Let's say that we have a school with several classes

Main List ( School ) ( contains list of (Class + Class Name + the Class note average )

Nested List (Classes)

--------- Name : CLass1 ( contains list of Students)

Student1
Name : Toto
Note : 8

Student2
Name : Titi
Note : 10

--------- Name : CLass2 ( contains list of Students)
Student1
Name : Tata
Note : 15

Student2
Name : Tutu
Note : 15

Student3
Name : Tete
Note : 10

so in my grouped collectionView i will have this :

Name : CLass1 --- Total_Note : 9 ((8+10) / 2)

Toto 8
Titi 10

Name : Class2 --- Total_Note : 20 ((15+15+10) / 3)
Tata 15
Tutu 15
Tete 10

So i would like to update the Total_Note every time that i change one student note.
I hope that it's more understandable.
 
Last edited:
How is MainList initialized? How does the CollectionView figure out what belongs to which group.

(I thought that this post was originally under WPF, and not it looks to have moved to MAUI.NET. Which framework are you using?)
 
How is MainList initialized? How does the CollectionView figure out what belongs to which group.

(I thought that this post was originally under WPF, and not it looks to have moved to MAUI.NET. Which framework are you using?)

I see it under
XALM code:
        <CollectionView x:Name="cv1" ItemsSource="{Binding Intervenants}" IsGrouped="True" SelectedItem="{Binding CalculNoteGenCommand }"  >
                <CollectionView.GroupHeaderTemplate >
                        <DataTemplate x:DataType="model:GroupList" >
                            <HorizontalStackLayout Spacing="15" HorizontalOptions="Center" Padding="5" Margin="2" BackgroundColor="LightGray">
                               <Label Text="{Binding Name}" BackgroundColor="LightGray" FontSize="20" FontAttributes="Bold" />
                                <alohakit:Rating IsReadOnly="True"  Value="{Binding Note_Gen, Mode=TwoWay}" Grid.Row="1" BackgroundColor="Green" UnSelectedFill="Beige" SelectedFill="ForestGreen" SelectedStroke="Azure" />
                            </HorizontalStackLayout>
                        </DataTemplate>
                </CollectionView.GroupHeaderTemplate>
                <CollectionView.ItemTemplate>

                        <DataTemplate x:DataType="model:UserShort">
                            <Frame CornerRadius="15" Padding="10" Margin="0,2,0,2" BackgroundColor="White">
                                <Grid ColumnSpacing="1" RowSpacing="5" ColumnDefinitions="Auto, *" RowDefinitions="*,*">
                                <Grid RowSpacing="2" RowDefinitions="Auto,Auto" >
                                    <toolkit:AvatarView ImageSource="{Binding Photo}" HorizontalOptions="Start"/>
                                        <Label Text="{Binding Alias}" Grid.Row="1" HorizontalOptions="Center" FontFamily="Metropolis Regular" FontSize="12" />
                                </Grid>

                                    <Grid Grid.Column="1" Grid.RowSpan="2" HorizontalOptions="Center" VerticalOptions="Center" >
                                        <alohakit:Rating Value="{Binding Note, Mode=TwoWay}" Grid.Row="1" HorizontalOptions="End" BackgroundColor="Green" UnSelectedFill="Beige" SelectedFill="ForestGreen" SelectedStroke="Azure"/>
                                     </Grid>                               
                            </Grid>

                        </Frame>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>


ViewModel:
 public ObservableCollection <GroupList> Intervenants
    {
        get
        {
            return intervenants;
        }
        set
        {
            if (intervenants != value)
            {
                intervenants = value;
                OnPropertyChanged(nameof(Intervenants));
            }
        }
    }
    
public EvaluateEventViewModel(UserService usrsvc, IConnectivity connectivity)
    {
        this.usrsvc = usrsvc;
        this.connectivity = connectivity;
        list1 = GetList1();
        list2 = GetList2();

        list3.Add(new UserShort { Alias = "Tony", Photo = "https://robohash.org/voluptateintempore.png?size=50x50&set=set1" });
        list3.Add(new UserShort { Alias = "Lisa", Photo = "https://robohash.org/voluptateintempore.png?size=50x50&set=set1" });
      
        Intervenants.Add(new GroupList("List1", 1, list1));
        Intervenants.Add(new GroupList("list2", 2, list2));
        Intervenants.Add(new GroupList("list2", 3, list3));

    }
 
It looks like Name on line 5 of you XAML binds to a Name property exposed by your GroupList that you are constructing on lines 27-29 of your view model. You GroupList can also expose a Note_Total. You can update that for each GroupList.
 
It looks like Name on line 5 of you XAML binds to a Name property exposed by your GroupList that you are constructing on lines 27-29 of your view model. You GroupList can also expose a Note_Total. You can update that for each GroupList.

Hi,

This is what i tried also to do. But impossible to find a solution.

class GroupList:
public class GroupList : ObservableCollection<UserShort> //, INotifyPropertyChanged
{
    //public event PropertyChangedEventHandler PropertyChanged;

    public string Name { get; private set; }

    public int Note_Gen { get; private set; }

    private ObservableCollection<UserShort> listObj;
    public ObservableCollection<UserShort> ListObj
    {
        get { return listObj; }
        set {
            listObj = value;
           // OnPropertyChanged("ListObj");
        }
    }

    public GroupList(string name, int note, ObservableCollection<UserShort> Listusers): base(Listusers)
    {
        Name = name;
        Note_Gen += note;
        ListObj = Listusers;
        ListObj.CollectionChanged += ListObj_CollectionChanged;
    }

    private void ListObj_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        Note_Gen = listObj.Sum(x => (x.Note));
    }
}

impossible to get any event when i changed a nested property.
 
It looks like Name on line 5 of you XAML binds to a Name property exposed by your GroupList that you are constructing on lines 27-29 of your view model. You GroupList can also expose a Note_Total. You can update that for each GroupList.

Hello,
thanks for your help. i solved my problem.
It seems that ObservableCollection make event only when we add/delete or move items in collection. When we simply update some properties in collection items collection don`t signalize about it and UI will not be updated.

So i found this class :

C#:
public class FullyObservableCollection<T> : ObservableCollection<T>
       where T : INotifyPropertyChanged
{
    /// <summary>
    /// Occurs when a property is changed within an item.
    /// </summary>
    public event EventHandler<ItemPropertyChangedEventArgs> ItemPropertyChanged;

    public FullyObservableCollection() : base()
    { }

    public FullyObservableCollection(List<T> list) : base(list)
    {
        ObserveAll();
    }

    public FullyObservableCollection(IEnumerable<T> enumerable) : base(enumerable)
    {
        ObserveAll();
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Remove ||
            e.Action == NotifyCollectionChangedAction.Replace)
        {
            foreach (T item in e.OldItems)
                item.PropertyChanged -= ChildPropertyChanged;
        }

        if (e.Action == NotifyCollectionChangedAction.Add ||
            e.Action == NotifyCollectionChangedAction.Replace)
        {
            foreach (T item in e.NewItems)
                item.PropertyChanged += ChildPropertyChanged;
        }

        base.OnCollectionChanged(e);
    }

    protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e)
    {
        ItemPropertyChanged?.Invoke(this, e);
    }

    protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e)
    {
        OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e));
    }

    protected override void ClearItems()
    {
        foreach (T item in Items)
            item.PropertyChanged -= ChildPropertyChanged;

        base.ClearItems();
    }

    private void ObserveAll()
    {
        foreach (T item in Items)
            item.PropertyChanged += ChildPropertyChanged;
    }

    private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        T typedSender = (T)sender;
        int i = Items.IndexOf(typedSender);

        if (i < 0)
            throw new ArgumentException("Received property notification from item not in collection");

        OnItemPropertyChanged(i, e);
    }
}

/// <summary>
/// Provides data for the <see cref="FullyObservableCollection{T}.ItemPropertyChanged"/> event.
/// </summary>
public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs
{
    /// <summary>
    /// Gets the index in the collection for which the property change has occurred.
    /// </summary>
    /// <value>
    /// Index in parent collection.
    /// </value>
    public int CollectionIndex { get; }

    /// <summary>
    /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
    /// </summary>
    /// <param name="index">The index in the collection of changed item.</param>
    /// <param name="name">The name of the property that changed.</param>
    public ItemPropertyChangedEventArgs(int index, string name) : base(name)
    {
        CollectionIndex = index;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
    /// </summary>
    /// <param name="index">The index.</param>
    /// <param name="args">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
    public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName)
    { }
}

Then implemented my class GroupList like that :

C#:
 public GroupList(string name, int note, FullyObservableCollection<UserShort> Listusers): base(Listusers)
    {
        Name = name;
        Note_Gen += note;
        ListObj = Listusers;
        ListObj.ItemPropertyChanged += ListObj_ItemPropertyChanged;
    }

    private void ListObj_ItemPropertyChanged(object sender, ItemPropertyChangedEventArgs e)
    {
        Note_Gen = listObj.Sum(x => (x.Note)) / listObj.Count;
    }

Thanks alot for your help.
 
Back
Top Bottom