1

My question is similar to this one: Bind to Count of List where Typeof

But how does this work for Classes?

In my MainWindow I have the following Collection and a Selected Count Property

private ObservableCollection<MyClass> _myClassCollection = new ObservableCollection<MyClass>();
public ObservableCollection<MyClass>
{
    get => _myClassCollection;
    set 
    {
        if(_myClassCollection == value) return;
        _myClassCollection = value;
        OnPropertyChanged("MyClassCollection");
    }
}

public int SelectedCount
{
    get => MyClassCollection.Where(x => x.IsSelected == true).Count();
}

public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

My MyClass:

public class MyClass : INotifyPropertyChanged
{
    // .. Properties
    private bool _isSelected;
    public bool IsSelected
    {
        get => _isSelected;
        set
        {
            if(_isSelected == value) return;
            _isSelected = value;
            OnPropertyChanged("IsSelected");
        }
    }
}

public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

So how can I "run" the SelectedCount Property, if the IsSelected Property of MyClass changed ? I want to show the number of Selected Items of the ObservableCollection in real time.

KushGene
  • 115
  • 1
  • 11
  • by the way, your code for `SelectedCount` is `O(n)`. Use it somewhere in a loop, e.g. for binding (that would lead to `O(n^2)`) and voila, you see a cpu core at 100% when your collection has ~500 items. – bohdan_trotsenko Jul 30 '18 at 14:48

3 Answers3

1

You can just add an OnPropertyChaned for SelectedCountin the setter of the other operations where a change may have occurred. For instance on setting the my class collection. This will tell stuff listening to that particular property something may have changed, get the value again.

set 
{
    if(_myClassCollection == value) return;
    _myClassCollection = value;
    OnPropertyChanged("MyClassCollection");
    OnPropertyChanged("SelectedCount");  // Make the change Here.
}

From the comments it would seem you need to listen to each element's property changed explicitly. Here is an example of how that would look in your setter with an event handler.

set 
{
    // remove subscriptions
    if(_myClassCollection != null) 
    {
       foreach(var element in _myClassCollection)
       {
          element.PropertyChanged -= ElementChanged;
       } 
    }

     // set to new collection
    _myClassCollection = value;

    // subscribe to new elements.
    if(_myClassCollection != null) 
    {
       foreach(var element in _myClassCollection)
       {
          element.PropertyChanged += ElementChanged;
       } 
    }

    OnPropertyChanged("MyClassCollection");
    OnPropertyChanged("SelectedCount");  // Make the change Here.
}



private void ElementChanged(object sender, PropertyChangedEventArgs e)
{
    if(e.PropertyName == nameof(MyClass.IsSelected))
    {
         OnPropertyChanged("SelectedCount");
    }
}

Now if you are adding or removing elements from your collection without creating a new collection, you will need to subscribe or remove subscriptions inside a CollectionChanged event handler.

Felix Castor
  • 1,598
  • 1
  • 18
  • 39
  • This doesn't work. I guess because `PropertyChanged` of `MyClassCollection` will not hit if the Property `IsSelected` on `MyClass` got hit. The `IsSelected` Property of `MyClass` is bind to `ComboBox.IsSelected`. So if I hit the combobox to select/unselect it, only the Event for `MyClass.IsSelected` will be hit. – KushGene Jul 30 '18 at 14:30
  • You will need to listen to the property changed of all of MyClass objects in your collection individually and call `OnPropertyChanged` when it is executed. – Felix Castor Jul 30 '18 at 14:36
  • But I can't call the `OnPropertyChanged("SelectedCount")` from `MyClass.IsSelected`. – KushGene Jul 30 '18 at 14:37
  • Seems still not to work. I add Items to the Collection via `MyClassCollection.Add(new MyClass ....)` Should I add items now in another way? – KushGene Jul 30 '18 at 14:58
  • There are a number of ways you can do that part. On creating a `MyClass` object you could just subscribe directly. Or start listening to the `MyClassCollection.CollectionChanged` event and subscribe there on adding. [Example](https://stackoverflow.com/questions/4588359/implementing-collectionchanged) – Felix Castor Jul 30 '18 at 15:11
1

You can use DynamicData to make it more readable:

var allObjects = new SourceList<MyClass>(); // this is what you populate with your objects

SelectedObjects = allObjects.Connect().Filter(x => x.IsSelected).AsObservableList();

If SelectedObjects is a public property, you can bind like:

<TextBloc Text="{Binding SelectedObjects.Count}"/>
Krzysztof Skowronek
  • 2,796
  • 1
  • 13
  • 29
0

You have to handle the CollectionChanged from your ObservableCollection. There you have to call OnPropertyChanged("SelectedCount") like in the linked Question.

In your set:

_myClassCollection.CollectionChanged += Handle_CollectionChanged;

In the event handler:

private void Handle_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    OnPropertyChanged("SelectedCount");
}
PinBack
  • 2,499
  • 12
  • 16
  • Doesn't work. I set the `CollectionChanged +=` line above `if(_myClassCollection == value) return`. I also updated my Question to give u more informations. – KushGene Jul 30 '18 at 14:49