I've been trying to figure out how to solve my problem for days.
I have a data structure similar to this (I use PropertyChanged.Fody library):
public class Item1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int Somma { get => this.Lista.Sum(o => o.Valore);}
public ObservableCollection<Item2> Lista {get; set;}
/*Other fields*/
}
public class Item2 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int Valore {get; set;}
/*Other fields*/
}
In my View I have two ListView like (lista is an ObservableCollection of Item1):
<mr:ListView x:Name="listView1" ItemsSource="{Binding lista}" SelectedItem="{Binding listView1Selected, Mode=TwoWay}">
<mr:ListView.ItemTemplate>
<DataTemplate>
<mr:ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Somma}" TextColor="Black" />
</StackLayout>
</mr:ViewCell>
</DataTemplate>
</mr:ListView.ItemTemplate>
</mr:ListView>
<mr:ListView x:Name="listView2" ItemsSource="{Binding listView1Selected.Lista}" SelectedItem="{Binding listView2Selected, Mode=TwoWay}">
<mr:ListView.ItemTemplate>
<DataTemplate>
<mr:ViewCell>
<StackLayout Orientation="Vertical" >
<Label Text="{Binding Valore}" TextColor="Black" />
</StackLayout>
</mr:ViewCell>
</DataTemplate>
</mr:ListView.ItemTemplate>
</mr:ListView>
When I call in my ViewModel.cs something that change the value of the field Valore of some Item2, I would like the Sum of Item1 to be recalculated and automatically binded. I tried replacing ObservableCollection with a class like:
public class ItemsChangeObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
public ItemsChangeObservableCollection() : base()
{
}
public ItemsChangeObservableCollection(IEnumerable<T> list) : base(list)
{
RegisterPropertyChanged(list.ToList());
}
public ItemsChangeObservableCollection(List<T> list): base(list)
{
RegisterPropertyChanged(list);
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
RegisterPropertyChanged(e.NewItems);
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
UnRegisterPropertyChanged(e.OldItems);
}
else if (e.Action == NotifyCollectionChangedAction.Replace)
{
UnRegisterPropertyChanged(e.OldItems);
RegisterPropertyChanged(e.NewItems);
}
base.OnCollectionChanged(e);
}
protected override void ClearItems()
{
UnRegisterPropertyChanged(this);
base.ClearItems();
}
private void RegisterPropertyChanged(IList items)
{
foreach (INotifyPropertyChanged item in items)
{
if (item != null)
{
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
}
}
private void UnRegisterPropertyChanged(IList items)
{
foreach (INotifyPropertyChanged item in items)
{
if (item != null)
{
item.PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
}
}
}
private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
But it still doesn't work. Can anyone please help me?
EDIT
Using the ItemsChangeObservableCollection class I can arrive into his method item_PropertyChanged when I update Valore field. So I would expect that calling
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
a CollectionChanged it's generated...but it isn't. If I add in Item1 constructor like
public Item1()
{
Lista= new ItemsChangeObservableCollection<Item2>();
Lista.CollectionChanged += MyCollectionChanged;
}
MyCollectionChanged is never fired. Why????
I realized what was wrong. The CollectionChanged hadler, that I tried to add in the Item1 Constructor, was overridden when I've instantiated the list in my viewmodel.
Adding CollectionChanged after the initialization in my view model resolve the problem.