Keelah
Keelah

Reputation: 302

Trigger RaisePropertyChanged from a different class

I'm having a class called Mod :

class Mod : INotifyPropertyChanged
{
    private bool serverSideChecked;
    private string name;

    public bool ServerSideChecked
    {
        get => serverSideChecked;
        set
        {
            serverSideChecked = value;
            RaisePropertyChanged("ServerSideChecked");
        }
    }

    public string Name
    {
        get => name;
        set
        {
            name = value;
            RaisePropertyChanged("Name");
        }
    }
}

and another class called Profile that contains a list of Mods

class ServerProfileNew : INotifyPropertyChanged
{
    public int ServerModsChecked { get => Mods.Where(m => m.ServerSideChecked == true).Count(); }

    private List<Mod> _mods = new List<Mod>();
    public List<Mod> Mods
    {
        get => _mods;
        set
        {
            _mods = value;
            RaisePropertyChanged("Mods");
        }
    }
}

Both classes implement INotifyPropertyChanged. I would need ServerModsChecked in Profile to update whenever ServerSideChecked is changed in Mod to have the total count of checked mods in real time.
Is that possible and how to do it ?

Upvotes: 0

Views: 39

Answers (2)

mm8
mm8

Reputation: 169200

Turn Mods into a read-only ObservableCollection<Mod> property and attach and attach/detach event handlers to/from the PropertyChanged event for any Mod item that gets added or removed:

class ServerProfileNew : INotifyPropertyChanged
{
    public ServerProfileNew()
    {
        Mods.CollectionChanged += (s, e) => 
        {
            if (e.NewItems != null)
            {
                foreach (object item in e.NewItems)
                {
                    (item as INotifyPropertyChanged).PropertyChanged
                        += new PropertyChangedEventHandler(OnModPropertyChanged);
                }
            }

            if (e.OldItems != null)
            {
                foreach (object item in e.OldItems)
                {
                    (item as INotifyPropertyChanged).PropertyChanged
                        -= new PropertyChangedEventHandler(OnModPropertyChanged);
                }
            }

            RaisePropertyChanged(nameof(ServerModsChecked));
        };
    }

    private void OnModPropertyChanged(object sender, PropertyChangedEventArgs e) =>
        RaisePropertyChanged(nameof(ServerModsChecked));

    public int ServerModsChecked => Mods.Count(m => m.ServerSideChecked);

    public ObservableCollection<Mod> Mods { get; } = new ObservableCollection<Mod>();

    //...
}

This should make the ServerModsChecked property always in sync with the source collection.

Upvotes: 0

Clemens
Clemens

Reputation: 128060

In the Mods setter, attach a PropertyChanged event handler to each element in _mods. In that handler, call RaisePropertyChanged("ServerModsChecked");.

Don't forget to detach the handler from the elements in the current _mods collection before.

public List<Mod> Mods
{
    get => _mods;
    set
    {
        if (_mods != null)
        {
            _mods.ForEach(m => m.PropertyChanged -= ModCheckedChanged);
        }

        _mods = value;

        if (_mods != null)
        {
            _mods.ForEach(m => m.PropertyChanged += ModCheckedChanged);
        }

        RaisePropertyChanged("Mods");
    }
}

private void ModCheckedChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == nameof(Mod.ServerSideChecked))
    {
        RaisePropertyChanged(nameof(ServerModsChecked));
    }
}

Upvotes: 1

Related Questions