I’m looking for a way to create grid rows that expand into a user-definable panel of controls. I’ve found a few possibilities that come close but don’t quite do what we want:
Do you have any suggestions?
Mike Saltzman said:You don't need unique UltraControlContainerEditor with two unique controls for each cell. You only need one for each type. So in this case, you would need an UltraControlContainerEditorA, UltraControlContainerEditorB, and UltraControlContainerEditorC. UltraControlContainerEditorA would need two instances of ControlA (one for editing and one for rendering). UltraControlContainerEditorB would need two instances of ControlB (one for editing and one for rendering). And so on for UltraControlContainerEditorC.
Okay, I can create multiple UltraControlContainerEditors as you suggest, but I'm not sure what to do with more than one of them. Following the online example for UltraControlContainerEditor, my code has a statement like:
this.ultraGrid1.DisplayLayout.Bands[1].Columns[0].EditorComponent = ce;
But of course that sets the container editor for all rows in the band. Is there a way to set the EditorComponent for specific row(s) within the band?
Actually, I realized your suggestion to have multiple UltraControlContainerEditors must go with the scenario of having multiple child bands, and a different editor would be assigned to each band, is that right? If we went with a single child band, that would mean only one UltraControlContainerEditor and one control for rendering (or for editing); would the control code have to check for something in the data type value and dynamically show/hide/create sub-controls to present different UIs for the different types?
Yes and no. You could do it with multiple child bands. That would simplify things a bit and you would only need to assign the UltraControlContainerEditor to each child band column once.
Another option would be to have a single child band and use the InitializeRow event of the grid In that event, you would examine the row to determine that it's a row in the child band. If so, you would get the parent row. And then you would use some value in the parent row to determine which UltraControlContainerEditor to assign to the Cell in the child row.
I have the implementation mostly working now. Still debating between single or multiple child bands, but for the moment am using a single band that is assigned the appropriate editor in the row initialization method.
A remaining issue concerns the interaction between the editing and rendering controls for a particular editor. You wrote:
Mike Saltzman said:Yes, you would probably just create a class that derives from Control or UserControl and place other controls on it. Whenever the Data property on the control is set, or some property on the data is changed, you would populate the UI for that control. When the user updates the UI, you would propagate that changed into the Data for that control instance.
That all works fine for the editing control: UI changes are propagated to the data member of the control, and the set accessor in turn populates the UI. But the rendering control (which is a separate instance of the same control) never has its data updated, and nothing triggers a refresh for its UI. So when I click off the control, edited fields revert to their original values; and when I return to edit that control, the modified values reappear. Is there a mechanism that is supposed to propagate changes in the editing control to the rendering control? Or do I have to find a way to do that manually?
Hi Jeff,
The way it works is that when the grid paints the cell (and it's not in edit mode), it gets the RenderingControl and sets the property you specified (RenderingControlPropertyName) to the value of the cell. So typically you just handle the setter of that property and then update the control's UI based on the new value. If this part wasn't working, then none of the cells of this column would be displaying the correct value(s) in the UI.
It sounds like the problem might not be in the rendering control, but rather than editing the cell is not properly saving the value and that therefore when you leave the cell, the RenderingControl is just getting the original value back. This is actually one of the trickiest parts of using the ControlContainerEditor. If the property on your control is an object and changing it in the UI sets a property on that object and doesn't change the object itself to a new instance and also send a notification (via INotifyPropertyChanged) then the cell's value has not actually changed. The cell's Value (and the control's value) are still referencing the same object and only a property on that object has changed. So in such a case, the grid doesn't know anything changed and doesn't get the new value from the editor.
So anytime you UI changes, you need to SET the property you are using. Not just set properties on that object, but set it to an entirely new instance of the object. And when that happens, you have to send an INotifyPropertyChanged notification.
Actually... I'm not 100% sure how far the grid and the editor go in this regard. Sending the INotifyPropertyChanged without actually changing the instance of the object might work just as well. In which case, your object type could implement INotifyPropertyChanged, which the control would then handle and essentially bubble up it's own INotifyPropertyChanged notification on the control.