1

I am passing a collection to UseSimpleClass. I would like UseSimpleClass property SimpleClassColCountChecked get to fire in when a value in a collection passed to UseSimpleClass changes.

In real life the collection is some user preferences and as they page through a useSimpleClass collection I want to preserve their preferences.

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private UseSimpleClass useSimpleClass;

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }


    public MainWindow()
    {
        InitializeComponent();
        List<SimpleClass> simpleCollection = new List<SimpleClass>();
        simpleCollection.Add(new SimpleClass());
        simpleCollection.Add(new SimpleClass());
        simpleCollection.Add(new SimpleClass());
        useSimpleClass = new UseSimpleClass(simpleCollection);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        useSimpleClass.SimpleClassCol[1].Checked = true;
    }
}

public class SimpleClass : INotifyPropertyChanged
{
    private bool _checked = false;

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    public bool Checked 
    { 
        get { return _checked; } 
        set 
        {   
            _checked = value;
            NotifyPropertyChanged("Checked");
            // clearly the next line does not work but that is what I want
            NotifyPropertyChanged("SimpleClassColCountChecked");
        }
    }
}

public class UseSimpleClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    public List<SimpleClass> SimpleClassCol { get; private set; }

    public Int32 SimpleClassColCountChecked
    {
        get
        {
            return (SimpleClassCol.Where(sc => sc.Checked).Count());
        }
    }

    public UseSimpleClass (List<SimpleClass> simpleClassCol)
    { SimpleClassCol = simpleClassCol; }
}
paparazzo
  • 44,497
  • 23
  • 105
  • 176

4 Answers4

1

My ObservableComputions library is what you need! With that library your code looks as following:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private UseSimpleClass useSimpleClass;

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }


    public MainWindow()
    {
        InitializeComponent();
        ObservableCollection<SimpleClass> simpleCollection = new ObservableCollection<SimpleClass>();
        simpleCollection.Add(new SimpleClass());
        simpleCollection.Add(new SimpleClass());
        simpleCollection.Add(new SimpleClass());
        useSimpleClass = new UseSimpleClass(simpleCollection);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        useSimpleClass.SimpleClassCol[1].Checked = true;
    }
}

public class SimpleClass : INotifyPropertyChanged
{
    private bool _checked = false;

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    public bool Checked 
    { 
        get { return _checked; } 
        set 
        {   
            _checked = value;
            NotifyPropertyChanged("Checked");
            // clearly the next line does not work but that is what I want
            NotifyPropertyChanged("SimpleClassColCountChecked");
        }
    }
}

public class UseSimpleClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    public ObservableCollection<SimpleClass> SimpleClassCol { get; private set; }

    private Computing<int> _simpleClassColCountChecked;
    public Computing<int> SimpleClassColCountChecked
    {
        get
        {
            if (_simpleClassColCountChecked == null)
            {
                _simpleClassColCountChecked = Expr.Is(() => SimpleClassCol.Filtering(sc => sc.Checked).Count).Computing();
            }
            return _simpleClassColCountChecked;
        }
    }

    public UseSimpleClass (List<SimpleClass> simpleClassCol)
    { SimpleClassCol = simpleClassCol; }
}

Take into account following:

1) Type of SimpleClassCol changed to ObservableCollection

2) Actual value you need is stored in SimpleClassColCountChecked.Value. SimpleClassColCountChecked returns an instance of INotifyPropertyChanged and notifies you when Value property changes. It occures when SimpleClassCol changes or Checked property changes.

Igor Buchelnikov
  • 505
  • 4
  • 14
1

This way, you can handle PropertyChanged event of SimpleClass in UseSimpleClass.

public UseSimpleClass (List<SimpleClass> simpleClassCol)
{ 
    SimpleClassCol = simpleClassCol; 
    foreach (var item in SimpleClassCol)
    {
        item.PropertyChanged += HandlePropertyChanged;
    }
}

private void HandlePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Checked")
        {
            NotifyPropertyChanged("SimpleClassColCountChecked");
        }
    }

For each item in source (simpleClassCol) you start listening for PropertyChanged event. May be it is not so expensive.

If it will be a ListBox (ListView), you can use SelectedItems collection to achive such behavior. So you will need two collection - first will contain whole items, second - selected items.

EDIT: The main part I forgot - is that you should specify DataContext of your MainWindow

Easy app

so, in the code behind

public MainWindow()
{
    InitializeComponent();
    List<SimpleClass> simpleCollection = new List<SimpleClass>();
    simpleCollection.Add(new SimpleClass());
    simpleCollection.Add(new SimpleClass());
    simpleCollection.Add(new SimpleClass());
    useSimpleClass = new UseSimpleClass(simpleCollection);
    DataContext = useSimpleClass;
}
stukselbax
  • 5,855
  • 3
  • 32
  • 54
  • Thank I added the handler but it is still not firing the get. The handler is fired and calls NotifyPropertyChanged("SimpleClassColCountChecked");. NotifyPropertyChanged receives the call and Info = SimpleClassColCountChecked. The problem is that PropertyChanged == null so it skips the PropertyChanged(this, new PropertyChangedEventArgs(info));. – paparazzo Mar 13 '12 at 14:04
  • I tried forcing a call to PropertyChanged(this, new PropertyChangedEventArgs("SimpleClassColCountChecked")); and it fails as PropertyChanged is null. There was no PropertyChanged event in UseSimpleClass. – paparazzo Mar 13 '12 at 14:10
1

You can use ObservableCollection<SimpleClass> (from System.Collections.ObjectModel namespace) and you don't need to handle changes - this collection implements ICollectionChanged interface and when it is changed (add, edit, remove items) data binding refreshes automatically

EvAlex
  • 2,888
  • 1
  • 20
  • 24
  • 1
    He changes the properties of an item in the collection. ObservableCollection does not notify for changes in the item itself. It just notifies as you said for changes in the collection. – Dummy01 Mar 13 '12 at 07:52
0

Yeah, ObservableCollection does not work.

But there are frameworks out there, witch try to solve those problems.

I made good experiences with Obtics => http://obtics.codeplex.com. here is a discussion over those frameworks. Bindable Linq vs. Continuous Linq

i am still looking for the "best" Solution for this issue, so please share your experiences :))

Community
  • 1
  • 1
Thomas Haller
  • 199
  • 1
  • 11