471,348 Members | 1,582 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,348 software developers and data experts.

Binding to INotifyCollectionChanged event

I am trying to bind a WPF dependency property to an aggregate of a
collection. I've implemented a wrapper around a Dictionary that
implements INotifyCollectionChanged to fire the event when items are
added or removed.

Debugging through it I notice that there is nothing listening to the
event after I bind to it which I expected the SetBinding to do as I
don't know what delegate to attach to the event. It's the binding that
needs updating after all.

I've tried a test with just an ObservableCollection to see if I was
missing something but that doesn't work either.

How do I wire up the event to the binding or do whatever it takes to
get my test to pass?

Here's my test code:

[TestClass()]
public class ObservableDictionaryTest : DependencyObject
{
public class MaxDoubleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object
parameter, System.Globalization.CultureInfo culture)
{
if (value is IEnumerable<double>)
{
return ((IEnumerable<double>)value).Max(); // using
Linq
}

throw new ArgumentException("Cannot covert " +
value.GetType() + " to IEnumerable<double>", "value");
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

public double Max
{
get { return (double)GetValue(MaxProperty); }
}

public static readonly DependencyProperty MaxProperty =
DependencyProperty.Register("Max", typeof(double),
typeof(ObservableDictionaryTest), new PropertyMetadata(0.0));

[TestMethod()]
public void TestBindingToObservableCollection()
{
ObservableCollection<doublevalues = new
ObservableCollection<double>();
values.Add(1.0);
values.Add(2.0);
values.Add(3.0);

Binding b = new Binding();
b.Converter = new MaxDoubleConverter();
b.Source = values;
b.Mode = BindingMode.OneWay;
BindingOperations.SetBinding(this, MaxProperty, b);

Assert.AreEqual(3.0, Max); // this works

values.Add(4.0);
Assert.AreEqual(4.0, Max); // this doesn't

values.Remove(4.0);
Assert.AreEqual(3.0, Max);
}
}
Jun 27 '08 #1
7 7870
What about using ObservableCollection<T>?

--
Pete
=========================================
I use Enterprise Core Objects (Domain driven design)
http://www.capableobjects.com/
=========================================
Jun 27 '08 #2
On 9 Jun, 16:22, "Peter Morris" <mrpmorris at gmail dot comwrote:
What about using ObservableCollection<T>?

--
Pete
=========================================
I use Enterprise Core Objects (Domain driven design)http://www.capableobjects.com/
=========================================
That's what the test I've posted does or do you mean use it in another
way? It's only my test class that is called ObservableDictionaryTest
(maybe I should have renamed it if that caused confusion).

I'd expect the Binding.Source setter to check if the source is
IEnumerable and if it implements INotifyCollectionChanged then listen
to the event and update the bound value when it fires.

I'm obviously not understanding how binding to an ObservableCollection
works.

Jun 27 '08 #3
>I am trying to bind a WPF dependency property to an aggregate of a
collection. I've implemented a wrapper around a Dictionary that
implements INotifyCollectionChanged to fire the event when items are
added or removed.

Debugging through it I notice that there is nothing listening to the
event after I bind to it which I expected the SetBinding to do as I
don't know what delegate to attach to the event. It's the binding that
needs updating after all.

I've tried a test with just an ObservableCollection to see if I was
missing something but that doesn't work either.

How do I wire up the event to the binding or do whatever it takes to
get my test to pass?
I think the problem is that only bindings which expect to bind to a
collection (like ListBox.ItemsSource) check for and subscribe to
INotifyCollectionChanged (though I don't know exactly how they do it).

What you could do is make your collection a property of your class, bind to
the property, implement INotifyPropertyChanged, then subscribe to the
collection's INotifyCollectionChanged yourself and raise a PropertyChanged
event. This seems rather clumsy and I'm sure there ought to be a better
way - maybe someone more knowledgeable will point it out.

Chris Jobson
Jun 27 '08 #4
On 9 Jun, 17:54, "Chris Jobson" <chris.job...@btinternet.comwrote:
I am trying to bind a WPF dependency property to an aggregate of a
collection. I've implemented a wrapper around a Dictionary that
implements INotifyCollectionChanged to fire the event when items are
added or removed.
Debugging through it I notice that there is nothing listening to the
event after I bind to it which I expected the SetBinding to do as I
don't know what delegate to attach to the event. It's the binding that
needs updating after all.
I've tried a test with just an ObservableCollection to see if I was
missing something but that doesn't work either.
How do I wire up the event to the binding or do whatever it takes to
get my test to pass?

I think the problem is that only bindings which expect to bind *to a
collection (like ListBox.ItemsSource) check for and subscribe to
INotifyCollectionChanged (though I don't know exactly how they do it).

What you could do is make your collection a property of your class, bind to
the property, implement INotifyPropertyChanged, then subscribe to the
collection's INotifyCollectionChanged yourself and raise a PropertyChanged
event. This seems rather clumsy and I'm sure there ought to be a better
way - maybe someone more knowledgeable will point it out.

Chris Jobson
Thanks.

One other idea I had was that it was the DependencyProperty that
needed refreshing so I tried subscribing to the event and calling
InvalidateProperty(MaxProperty), but that didn't work either, it still
came out as 3.0 somehow and the Convert was never called again so the
3.0 isn't being invalidated.

I'll try your idea since the collection will be a property of a
UserControl once I get it working.
Jun 27 '08 #5
>I am trying to bind a WPF dependency property to an aggregate of a
collection. I've implemented a wrapper around a Dictionary that
implements INotifyCollectionChanged to fire the event when items are
added or removed.

Debugging through it I notice that there is nothing listening to the
event after I bind to it which I expected the SetBinding to do as I
don't know what delegate to attach to the event. It's the binding that
needs updating after all.

I've tried a test with just an ObservableCollection to see if I was
missing something but that doesn't work either.

How do I wire up the event to the binding or do whatever it takes to
get my test to pass?
I think the problem is that only bindings which expect to bind to a
collection (like ListBox.ItemsSource) check for and subscribe to
INotifyCollectionChanged (though I don't know exactly how they do it).

What you could do is make your collection a property of your class, bind to
the property, implement INotifyPropertyChanged, then subscribe to the
collection's INotifyCollectionChanged yourself and raise a PropertyChanged
event. This seems rather clumsy and I'm sure there ought to be a better
way - maybe someone more knowledgeable will point it out.

Chris Jobson
Jun 27 '08 #6
After looking into this a bit more I found
http://www.drwpf.com/Blog/Default.as...=36&EntryID=18 that told
me that it is a CollectionView that does the subscribing to
CollectionChanged in ListBox and the like.

Naturally I tried wrapping my collection in a CollectionView and
setting that as the source but now the Max property doesn't get
evaluated at all (my converter is never called) so thebinding is
treating the view differently to any other plain IEnumerable, like it
thinks it doesn't need to do anything if it already has a
CollectionView.

This seems like one of those times when I'm digging deeper than I need
to and all this clever Binding and CollectionView stuff does what I
need if only I knew how to use it properly.
Jun 27 '08 #7
After looking into this a bit more I found
http://www.drwpf.com/Blog/Default.as...=36&EntryID=18 that told
me that it is a CollectionView that does the subscribing to
CollectionChanged in ListBox and the like.
Thanks for that link. I'd read it some time ago but had forgotten the bit
about CollectionView.
Naturally I tried wrapping my collection in a CollectionView and
setting that as the source but now the Max property doesn't get
evaluated at all (my converter is never called) so thebinding is
treating the view differently to any other plain IEnumerable, like it
thinks it doesn't need to do anything if it already has a
CollectionView.
I *think* (but could well be wrong - I find it all a bit confusing!) it's
still the same problem - binding Max to a CollectionView is more or less the
same as binding it to an ObservableCollection, and in both cases a change to
the collection won't re-evaluate Max because it isn't interested in
INotifyCollectionChanged. AIUI the special feature of CollectionView is that
it if your property is of type CollectionView then you can bind a collection
to it and the property will re-evaluate when the collection changes.

(By the way, I'm surprised your idea of InvalidateProperty(MaxProperty)
didn't work. I've never used InvalidateProperty myself, but from the
description in MSDN it sounds ideal.)

I've just come across what might be another solution to your problem -
BindableLINQ (http://www.codeplex.com/bindablelinq/). In particular this
post (http://www.paulstovell.com/blog/bind...ble-aggregates)
seems to describe something very similar to your requirement. It's only a
beta, and I've no experience of it myself, but it might be worth
investigating.

Chris
Jun 27 '08 #8

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by Rodrigo Benenson | last post: by
1 post views Thread by Marcin Floryan | last post: by
1 post views Thread by Jonathan Yong | last post: by
11 posts views Thread by Rourke Eleven | last post: by
19 posts views Thread by Simon Verona | last post: by
reply views Thread by Larry Serflaten | last post: by
6 posts views Thread by Mikus Sleiners | last post: by
6 posts views Thread by Dmitry Duginov | last post: by
reply views Thread by Ronak mishra | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.