I would like to fire an event after the commit of a cell edit. I.e. after the cell has updated the value it's bound to.
I've tried the techniques mentioned here http://wpf.codeplex.com/Thread/View.aspx?ThreadId=39356
But none of them work for me.
A little more detail: we need to use data binding on classes that don't implement the INotifyPropertyChanged, and have properties that are collections, that doesn't implement INotifyCollectionChanged. To make these work better with WPF DataBinding we are generating
proxy objects on the fly. These proxy objects are of a type that implements INotifyPropertyChanged, and have the exact same properties as the objects they wrap.
The collections in the collection properties, are wrapped with new collections that implement INotifyCollectionChanged.
If the collections are collections of primitives, the proxy collections becomes collections ot a TypeWrapper<primitive> where TypeWrapper takes care of notification on change.
However, if the collections are collections of objects with properties, the proxy collections item type is the same type as the item type of the wrapped collection.
And for these collections we trigger notifications for all operations that changes the number of rows in the DataGrid. But we don't trigger notification when a property on a collection item is changed.
The problem is that the DataGrid touches the individual collection elements without notifying the collection that they have changed (if it e.g. had re-called the setter of the items that would have worked).
I first created an event handler for CellEndEditing, but that is called too early. If I force notification of the collection then, it can detect no difference from its previous item values, and nothing happens.
As for the techniques in this post http://wpf.codeplex.com/Thread/View.aspx?ThreadId=39356 :
- Using a Dispatcher.BeginInvoke I succeeded in calling the delegate, but nothing happened, which means it was probably called too early as well
- Using Binding.AddSourceUpdatedHandler the handler was never called (which is not surprising since if a source update had been triggered I wouldn't have had this issue in the first case)
I also tried using Binding.AddSourceUpdatedHandler on the datagrid columns. That gave no error when compiling, but failed with an exception at runtime.
I guess I could try something hacky like forcing a collection notification when edit starts on a new cell....? (not really... just a stray thought)
Another solution would be to proxy the collection elements as well, with something that implements INotifyPropertyChanged. But this madness needs to stop at some point. We have already spent a lot of time on this proxy class generation.
All hints, and tips and ideas are welcome!
Conceptually this could have been fixed in two ways:
1. If the DataGrid could be convinced to call the property setter of the property bound to its itemssource, every time it has changed one of the collection's items
2. If the columns could be convinced to trigger source changed notification events and there was a way to hook up to them
For alternative 1, we've tried to provoke this behaviour by binding to IEnumerable properties returning read only collections. But it still changes the individual collection items directly (that's why it mostly seem to work, because the source object property
refers to the same objects the DataGrid is changing, but there is no data binding updating going on).
For alternative2, it is possible to get hold of the Binding, and make it emit source update notification events. But there is no way to attach a handler directly to the column. And I don't know how to attach a handler to the Control doing the actual edit
(i.e. the TextBox or ComboBox or whatever, where the edit occurs). Are these Controls cached and reused? Or are they created on the flow to do the edit?
I thought about a hack where I added a validator, or set a custom converter to the binding from the columns to properties on the collection items. But like the CellEndEditing event, they would be called too early (i.e. before the value has been set in the