ComboBox doesn't handle NotifyCollectionChanged, when bound in code to a Collection

I am switching the ItemsSource binding for a ComboBox on the fly, in code. When I do so, it appears that the ComboBox isn't registered for the

NotifyCollectionChanged Event

As a result, it does NOT pick up changes to the bound collection.

I would expect WPF to wire this up automatically when I set the binding




Answer this question

ComboBox doesn't handle NotifyCollectionChanged, when bound in code to a Collection

  • SekharPC

    Try wrapping the change to the ItemsSource in a BeginInit()...EndInit() block.

  • Hi_4_All

    I'm a little skeptical because at one point I implemented the INotifyCollectionChnage and the Collection as a property on the binder itself. I fired CollectionChanged events, but I could see that the invocation list for the event was empty, so it seemed that the binding system was not listening to the CollectionChanged event as one would expect. Maybe your right and the binding only triggers on the PropertyChange.

    At this point, I have enough of an implementation for my proof of concept, I will explore your suggestion when I get down to the actual implementation. In the mean time, I'll have lots of fun question about how to do Validation well beyond the intent of the original WPF design :))

    Thanks again for all the help Mike

    NIK

    PS. Boy I wish someone from MS would chime in on this.



  • rgalgon

    NotifyCollectionChanged Occurs when the collection changes(either by adding or removing an item) not the itemssource

    Am I missing something



  • logtorahul

    Ok, something is definitely busted with DataBinding and ItemsControls.

    Regardless of whether I use a combo or list box, I have the same problem.

    I hacked in a reference to the UI element in my source object so that I could explicitly call UpdateTarget to force the new Collection to be be picked up, this slaps data in the control, but the original data is still there and I can't even remove it myself because the "ItemsSource is in use".  What a nightmare.

    The original problem exists. ComboBox does NOT pick up changes in manually bound collections.

    Anybody got any insight into this MS

     

     



  • avaya12

    Yes, Mike is correct, when the collection change is completed I call this

    NotifyCollectionChanged(NotifyCollectionChangedAction.Reset);

    and fire the event (which I have verified by catching it myself in other code).



  • redcodes

    This was something I was going to dive into for you. Does your object that you are binding to implement INotifyPropertyChanged and does your property setter fire the event Basically in your binding, you are binding to the Property on the Object itself...your object is responsible for notifying the binding system that it has changed.

    Basically, when the binding is setup even though to you it is pointing to a property on an object, it is in reality pointing to the object that the property points to. So unless someone notifies the binding system "hey this property is pointing to a different object", the binding still resolves to the original object.

    So what you need to do is implement INotifyPropertyChanged on the class that you are using for the binding and make sure that the setter for any property that you want to alert listeners on a change fires the PropertyChanged event.



  • ThunderRock

    Also, this is well past the Init stage, so BeginInit, EndInit won't help me.

    I have the age old problem of operating from the Source, so I have no context about the Target and WPF makes it near impossible for me to get to the target control.

    I did see an InvalidateProperty method. Is that what you were refering to



  • Mike Wilson

    Exactly. Binder should implement INotifyPropertyChanged and the Setter for Binder.Values should fire the PropertyChanged event.

  • Robin Debreuil

    The short version:

    I was binding the ItemSourceProperty of ComboBox to an ObservableCollection which was implemented as a property on my Source object.

    When I did so, the combo box didn't pick up changes to the collection, even though I was firing the INotifyCollectionChanged event.

    I resolved the problem by deriving a collection class from ObservableCollection and implementing the collection as a public member class of the source object, rather than as a property. When I did this, all the collection plumbing seemed to work properly and changes were reflected in the Combo Box.

    I never got an answer on why the property approach didn't work, be happy to spend some time on it if someone wants to help figure out what was going wrong.



  • DaveDB

    If you're reassigning a collection to the ItemsSource, I believe it should be within the confines of a Begin/EndInit block because you're essentially reinitializing your ItemsControl.

    Like someone mentioned earlier, NotifyCollectionChanged only fires when an item is added, removed, or modified within the collection. In order for that to work, there has to be a listener for the event. The listener is most likely attached during the initialization phase. Of course I could be wrong, the ItemsControl may have a handler for the ItemsSourcePropertyChanged that rewires the the listener to the new ItemsSource collection's NotifyCollectionChanged event...but judging from your experience, that's not what's happening.



  • Robert Palmer

    Tried performing the re-binding within Begin/EndInit block, but the results (non-results) are the same.

    I verified previously that there are no listeners on the NotifyCollectionChangedEventHandler that the source object implements.  Looks like there is some built-in handler code in the System.Collections.Specialized namespace.  I was looking at Sheva's sample code and noticed that he wasn't binding to a property, but to an ObservableCollection object instance.

    I was implementing the Collection as a property on my bound object, I reworked it such that the Collection derives directly from ObservableCollection and is exposed as public member class to make sure I got all the proper plumbing in the proper places. Voila, it appears to work. 

    Hopefully someone from MS will chime in and explain the nuances of this to me, but for now at least I can start beating a different horse to death.

    Thanks for all the help folks.

    - Validation here I come.

     

     

     

     

     

     



  • StephenMas

    Not sure that what I am seeing is consistent with that, but I would like to understand the details.

    Currently my implementation is working because I am binding to a member class derived from ObservableCollection. Unfortunately using a class is ugly because I have to backdoor it to mopdify the collection if the underlying data changes (yuk).

    Here's how it works now:

    1) Control.ItemsSource is bound to temporary binder (helper) object. (Binder.Values)

    2) At load time, TreeWalker runs and invokes the binder object on the appropriate controls (those with bindings), the binder object clears the existing binding and sets up all the new ones.

    3) Binder object calls SetBinding from Control.ItemsSource to actual business logic object - BizObj. (Note: does not specify a property name, but does specify the member class (eg. BizObj.Values))

    Previously:

    Step 3) The binder object bound the Control.ItemSource to BizObj.Values, but Values was a property (complete with get). The binding system did call the get to retrieve the data, so it was clearly pointing at the right thing. I was firing both PropertyChanged and CollectionChanged notifications from BizObj, but they were ignored by the bound item.

    Are you saying that I needed to raise the PropertyChanged event on the Binder.Values property (and by extension the object itself) after I cleared the binding to it and set the new binding to BizObj.Values




  • SimonOng

    This is true...but apparently his UI isn't being alerted to the change...I think there is some kind of refresh method on the ItemsControl that forces any bound UI to update its display.

  • Etowah_man

    Would you give me a outline of the code you have.

    Which class, with which property and implementing which interfaces.

    And what you are binding to which classse/properties...and what you expect to happen and what is'nt happenning.

    Happy to help, but I can't fully grock what you're trying to do.



  • ComboBox doesn't handle NotifyCollectionChanged, when bound in code to a Collection