I have a tree in Grid view, bound to a list (which is a custom type derived from BindingList) of objects (which implement INotifyPropertyChanged). One of the columns is of type CheckState (set in code, since the Designer doesn't know about that type), and is bound to an object property which is declared as CheckState. All of these properties default to unchecked.
Here's the behavior: if I check the checkbox on one item, nothing happens (that is, the property on the object does not get set). If I now check the checkbox on a second item, the property on the *first* item is set, but not the property on the second item. If I check a third item, the second item will get set, and so forth. When the property is modified, I am firing the PropertyNotified event like I'm supposed to.
This is pretty clearly something wrong with my code. Any idea what I could be doing to cause this behavior?
Thanks, Aaron
The reason that it's a BindingList<Object> is so that I can have a multilevel tree of objects. In other words, I want to be able to have a CustomerCollection of CustomerCollections of Customers (this is analogous to something that I'm doing in my real code, I don't claim it makes sense in this context).
If I define CustomerCollection as BindingList<Customer>, then I can't have collections of collections. How would you suggest that I define a multilevel data structure to which I can bind the tree?
I'll investigate why the ListChanged event is not being fired.
After looking at the sample again, I'm a bit confused. I think the problem here is probably that you are using BindingList<Object> instead of BindingList<Customer>.
But I'm not sure why you are using Object or why you are adding a collection into the collection. In fact, I'm surprised that this code works at all - this data structure is really odd.
It seems to me that you should be definining your Customer object to return a CustomerCollection of child items. Then you root BindingList contains individual Customer items, each of this has a collection of child items. That way the CustomerCollection can derive from BindingList<Customer> and I bet that fixes the issue of the property change notifications.
Hi Aaron,
aaronsher said:Thanks, but my understanding is that BindingList<T> will automatically subscribe to the PropertyChanged event of any objects added to it (as per the example at http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx).
I was not aware of that. But it's not happening here. You can hook the ListChanged event of the collection class yourself and see that it never gets called. There's nothing the tree can do about that.
aaronsher said:Could the problem be that I've actually got two levels of lists? In order to get the tree to show two levels, I have to actually provide it three levels of data, meaning that I have a list containing a list containing objects. If the BindingList behaves as I expect, it will catch the property-changed notifications from the Customer objects and translate them into events through its IBindingList interface, but maybe the outer list won't transfer those to the tree view?
Since it's not working on the root level, I doubt it has anything to do with the levels.
aaronsher said:However, after a bit more thought, there's a problem with your suggestion of what's going on. If the problem were that the event was getting dropped, then the tree view would have no reason to query the property at all, ever, so the checkbox wouldn't get updated until something else occurred (like a selection in the tree). Right?
No, my suggestion is completely consistent with that is happening here. The tree is not getting notified that anything changed so it's not updating it's display. When you mouse over the cell or you call Invalidate, then tree re-paints the cell and gets the values from the data source again, anyway.
OK, that didn't work (the ListChanged event never gets fired), and I'm not sure why. However, after a bit more thought, there's a problem with your suggestion of what's going on. If the problem were that the event was getting dropped, then the tree view would have no reason to query the property at all, ever, so the checkbox wouldn't get updated until something else occurred (like a selection in the tree). Right?
In fact, simply calling Invalidate on the tree causes it to update all of its checkboxes, as does just mousing over its area. This suggests to me that its data is already up to date, and the only thing that is missing is the repaint event.
Have I missed something?
Hm, there's an issue with that approach: the PropertyChanged event wants to get the name of the property that's been modified. If I just bubble the event up through, the receiver is presumably going to look for a property with that name on the list object, and it won't be there.
Does the UltraTree pay attention to the name of the property that's been modified? If not, it won't matter what name I pass.
Another possibility, probably a better one in fact, is to add code to the collection object to check to see if the object added supports the IBindingList interface, and to subscribe to its events if so and trigger my own events from there. That way, the original PropertyChanged event would immediately become a ListChanged event as expected, and would get translated appropriately as it went up the tree.
Aaron