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
OK, I reread your previous post. You're correct, if I had a Customer at each level of the tree and a Customer could have a list of sub-Customers, that would probably solve the problem. Unfortunately, I don't want a customer at each level; the collections have their own fields (represented by Index in this example) that I need to display.
So, I've created a base class named TreeNodeOb that implements INotifyPropertyChanged and provides a BindingList<TreeNodeOb> as one of its properties, and derived both Customer and CustomerCollection from that class. Now, I have more or less what you suggested - a data structure with an object at each level that provides property-changed notifications. I now need to bind the tree to the Children property of my base-level object, but that's OK.
So, that's good progress, thank you. That just leaves my secondary question: is there any way to support recursive updates from the higher-level checkboxes? That is, if I check a group, I want to check all the items contained within that group. Unfortunately, since the update doesn't occur until I leave the cell, I have no way to make that happen immediately. Is there any way to force the update to occur immediately? Can I detect the click in the checkbox somehow and force a refresh?
Hi Aaron,
There's no event for this directly on the tree control. But you could hook the ValueChanged event of the column's editor.
private void Form1_Load(object sender, EventArgs e) { this.ultraTree1.SetDataBinding(this.ultraDataSource1, "Band 0"); this.ultraTree1.ColumnSettings.AllowCellEdit = Infragistics.Win.UltraWinTree.AllowCellEdit.Full; this.ultraTree1.Override.CellClickAction = Infragistics.Win.UltraWinTree.CellClickAction.EditCell; this.ultraTree1.ColumnSettings.ColumnSets[0].Columns["Column 0"].EditorResolved.ValueChanged += new EventHandler(EditorResolved_ValueChanged); } void EditorResolved_ValueChanged(object sender, EventArgs e) { EmbeddableEditorBase editor = (EmbeddableEditorBase)sender; UIElement elementBeingEdited = editor.ElementBeingEdited; if (elementBeingEdited == null) return; UltraTreeNodeCell cell = editor.ElementBeingEdited.GetContext(typeof(UltraTreeNodeCell)) as UltraTreeNodeCell; Debug.WriteLine("Node " + cell.Node.Index.ToString() + " checkbox set to " + editor.Value.ToString()); }
Thanks, that's perfect. Having done that, what's the best way to tell the editor to commit its changes immediately? I've tried calling ExitEditMode, both directly and by using Invoke on the form, but it seems to undo the changes (as in, the checkbox is still unchecked afterwards), regardless of what parameters I pass it.
A secondary question - the ValueChanged handler gets called twice. Do you know why? Not that big a deal, but for efficiency's sake I'd like to do the operation only once.
Never mind the commit question, I figured out that using BeginInvoke instead of Invoke (which of course doesn't do anything, since we're already on the main thread) makes it work.
I'm still curious about the double calls, though.
For some reason, in my real application, the handler is actually called four times for each click, making that secondary question a bit more important. It works nicely, though, if a bit slowly.
I don't see any reason why that behavior would change. But if you want to be safe, you could create an editor and assign it to the column and then hook the ValueChanged on each one separately. Or assign the same editor that you created to both column and hook the event once. Either way, this would mean you are no longer relying on the default editor in the column and you would be immune to any future changes in functionality. :)
OK, that's fine - as long as the behavior isn't going to change in the next version, there's no problem. Thanks for all your help.
Aaron
My guess is that you are using the same editor for both columns (which is perfectly valid) and so if you hook the editor on each column, you are really hooking the same editor twice.
If you are not assigning an Editor or EditorComponent to the column, then the tree creates one internally and it will re-use the same one for multiple columns.
OK, several things were going on here. First, yes, I was hooking the event more than once (that is, my code to hook the event was getting executed multiple times); fixing that reduced the calls from four to two. I'm hooking the event on two different column sets, so I tried disabling one of them and that brings it down to one, and in fact the event continues to get hit even if I click the checkbox in the other column set.
This makes me nervous, because my guess is that it's working by coincidence. Is the editor control shared between column sets? Can I rely on that continuing to be the case forever?
My only guess is that you are hooking the event more than once. I hooked mine in Form_Load so it only gets hooked once, and I only got the event once for each click on a checkbox.
Put a breakpoint on the line of code where you are hooking the event and see if it's getting hit mode than once.
If that's not the case, then I don't know why that's happening. Maybe you could put a breakpoint in the event handler and look at the call stack to see where the event is being fired from each time.