Using Infragistics 8.2
Hello, All-
I've done some reading on using Creation and Draw Filters, but I need assistance with designing a solution for the following problem:
We have a grid of data with the following datatable schema:
Id, Name, Attribute1, Attribute 2, Score
The Score is a sort of calculated field based on several user-input fields, but none of these inputs are stored in the actual grid.
What we'd like to do is have the GroupBy knobs appear next to each row in the grid, but when the knob is expanded, we inject our own UserControl as the child UIElement that will fill up the space between the rows (while it is exapnded). This child control will do some calculations and take user input and update the Grid's Score column based on user input.
So, the 2 main questions are:
1) How would I create the grid to show knobs (assuming using GroupBy functionality?) when the grid doesn't have any concept of aggregation that would cause multiple rows to group? Would I just groupBy ID (ID will be unique) and so the summary row will show the knob and the default expand behavior will be to show the 1 row that has the Group ID?
2) Once I have the GroupBy functionality such that the rows have knobs that expand, would I use a creation filter or draw filter to halt the creation of the child UI elements, and create my own child which is my custom UserControl which takes the user input and modify's the grid's datasource's Score field?
I'm sorry if this is confusing, I'm trying to explain it as straight forward as I can, but if there's anything that i'm leaving out (due to ignorance of the WinGrid's GroupBy capabilities) please let me know and I'll try to fill in the blanks. I purposely left out where the custom child UserControl will store and modify the User Input data because I do not want to confuse the core question about how to get GroupBy rows to show custom UI controls in their children. I think once i get that behavior nailed down, I can get the code to do the correct work about updating the datasource's Score field.
-Chris
Hi Chris,
I'm having a little trouble understanding the relationship between the UserControl and the score column.
It sounds to me like you maybe what you want here is not an expandable field in the grid, but rather a dropdown in the score column. This would be very easy to implement using an editor. You could add a dropdown button to the column that drops down a custom control you create and it would be much simpler and easier than trying to insert a control in between rows of the grid.
If you have to do this in such a way that the usercontrol is visible within the grid in a more permanent way, and it's not just a dropdown, then I think this will be very difficult to achieve.
But, if you must do that, then what I would probably do is change your DataSource to have a hierarchy. You could use a DataSet, for example, and add a child table with a single column and relate the child table to the parent table which contains the information you are currently displaying in the grid.
You would add a single child row for each parent row, thus giving you the expansion indicators and a single cell in the grid that can be expanded for each parent row. So this essentially carves out a space for you to put your UserControl and handles all of the expand/collapse functionality for you.
Then all you have to do is place your control in the cell. This part would be easier if you updated to a newer version of NetAdvantage, because then you could make use of the new ControlContainerEditor. It would save you quite a lot of work.
But if that's not an option, then what you could do is use a CreationFilter to watch for the creation of the CellUIElement for the child cell and position a control at that point in the grid using the same rect.
But this is not a trivial implementation. You will need multiple instances of your usercontrol because more than one row of the grid could be expanded at any time. You will also need to handle removing the usercontrols when the rows are hidden or scrolled out of view. I'm not sure how you would handle what happens when a control needs to be partially scrolled out of view, either.
Hi Mike,
Thanks for your advise there, I knew this was going to be complicated. The reason why this is as simple as creating a simple editor for the score field is because the UserControl that is being used to collect input from the user is quite complicated: It contains several dropdowns which drive subsequent fields (Example, first dropdown gives a chose of 'Methodologies', which drives the second dropdown which is some sub-choice based on the selected methodology), then once those choices are made, they apply an adjustment value, and comments to justify the user's adjustments, and then finally the UserControl performs a calculation based on the methodology, adjustment, and other values that will derive a score. The UserControl is a sorta 'mini-form' within the grid that provides a 'robust' UI to the users just to help them enter the data for the Score field in the grid. Note, they never enter any data in the score field directly (so the Score cells are all read-only) but the UserControl is not read-only so that's how they go in and manuipulate the Score fields for each row.
As you can imagine, all of these fields will not fit very nicely into an custom editor for the cell. In fact, based on the layout mockups, it will take up the entire width and possibley a few 'row heights' due to the number of fields and they way they want it laid out.
So, I'll go with your Plan B approach: I already know I'm going to be translating an object structure into a DataTable (which will be my datasource) but in order to get the expand/collapse behavior, I'll create a new DataTable with the single column in it that will be used as a dependent table (as you describe above). I guess the work here is that I'll create a DataSet, use my existing DataTable with the Score rows, and then create another DataTable with an ID column, add it to the DataSet, and then hook up a foreign key relationship? I think that's how I make hierarchical datasources, but I'll go google that.
Once that's done, I'll Implement the CreationFilter as you described above (which should be sorta easy considering it's only 1 cell so the space will already be allocated for me within the grid, I just hope that it handles resizing contents automatically (as in it will stretech the cell's rect to fit the child UserControl)...I'd hate to manage resizing manually...but I'll find out.
Finally, Yes, it's understood that for each row there will be an instance of my UserControl to provide the UI for the Score editor. I'm not sure yet if it creates it all up front of if the instance is creating as the row is expanded, but I'll find that out soon enough too.
Thanks again for your insight on this, I have a good plan now and I'll let you know if there's any problems.
cknoll said:I guess the work here is that I'll create a DataSet, use my existing DataTable with the Score rows, and then create another DataTable with an ID column, add it to the DataSet, and then hook up a foreign key relationship? I think that's how I make hierarchical datasources, but I'll go google that.
Yep, that's basically how it works.
cknoll said:I just hope that it handles resizing contents automatically (as in it will stretech the cell's rect to fit the child UserControl)...I'd hate to manage resizing manually...but I'll find out.
The methods of the CreationFilter will get fired any time the cell is resized, so as long as your code sizes the UserControl or whatever to the size of the cell, it will be fine.
cknoll said:Finally, Yes, it's understood that for each row there will be an instance of my UserControl to provide the UI for the Score editor. I'm not sure yet if it creates it all up front of if the instance is creating as the row is expanded, but I'll find that out soon enough too.
You will only need to create one instance for each one cell visible on the screen. The one's that are off-screen will not have any UIElements created for them.
Mike,
Would you recommend using an existing UIElement class for this, or do you think I should create a new UIElement subclass (perhaps UserControlUIElement)?
If you plan to position a control over the cell, then you don't even need a UIElement. You could just position the control.
Of course, this leaves you with the problem of how to display a control that is partially scrolled out of view.
So what you might want to do is create a UIElement which takes a snapshot of the control and draws it into the cell. In which case, you would probably want to derive your own class from UIElement.
This is, in fact, what the UltraControlContainerEditor does for cells that are not in edit mode. You could save yourself quite a lot of time and effort by simply upgrading to the latest version of NetAdvantage and using this component. It has already done a lot of the work you will have to do.
I seriously wish I could do that. The Render control and Edit control looks like this is exactly what I need.
Unfortunately, the 8.2 version of Infragistics is used broadly throughout our custom framework which is used across many applications, so in order to upgrade, it would involve a lot of regression testing time for all applications (paranoia I know, but they very important applications). So for now, it's just not possible. I even asked if we could just use a popup when they double click the cell that this input form is used for, but still..nothing. I wanted to just use a custom editor (like there'd be a dropdown on the column and when they expand it it shows the custom form) but still...no go. So i have to make this work.
So, back to the problem:
If I want to draw the user control into the cell, then I guess I just overide the paint method of the UI element and just draw the UserControl to a bitmap and then paint that bitmap onto the cell. Do I also set the EditorControl (i thinkthat's the property) to the user control so that when the cell is clicked, the actual user control will be brought into focus so the user can interact with it?
My origional idea with this approach was that the creation filter was going to create a custom UIElement wrapper for my user control so that I wouldn't have to do this 'override paint' operation to draw the controll....the thought was that the control would be physically in the cell, but it sounds like you're saying that the only thing that can exist in the grid cells are UIElements which is sorta an abstraction layer from the physical controls, and they physical controls are only hooked up for user input if the cell is being edited?
Admittedly I need to do more experimentation so I have less questions, but that's the phase I'm at right now.
Hi,
Let me know if you need any additional help.
Regards,
Stefaniya
You have a couple of options here.
If you want to go all out, then you will want to write an Editor. Personally, I would advise against this. Even if you have the NetAdvantage source code to use as a guide, writing your own editor is a pretty daunting task. The UltraControlContainerEditor took several weeks of development time for us to write, and we're pretty familiar with editors and how they work. Of course, your editor doesn't have to be as generic, so you could cut some corners and make assumptions that we cannot.
The alternative solution is to just sort've fake it and position the control over the cell, which is what I recommend you do.
cknoll said:If I want to draw the user control into the cell, then I guess I just overide the paint method of the UI element and just draw the UserControl to a bitmap and then paint that bitmap onto the cell.
Yes, what you do is create a UIElement-derived class and override OnDrawBackColor or OnDrawImageBackground. Your derived element will have to look at it's own parent element or call GetContext on itself to get a reference to the cell and you can them work from there.
cknoll said:Do I also set the EditorControl (i thinkthat's the property) to the user control so that when the cell is clicked, the actual user control will be brought into focus so the user can interact with it?
No, you can't do that unless you go the full blown write-your-own editor route. You can't assign just any control to this property, it has to be an IProvidesEmbeddableEditor, which needs to return an EmbeddableEditorBase, which needs to create EmbeddableElementBase elements and handle a whole lot of stuff that I don't think you want to get involved in. Or maybe you do, I don't know how much time you are planning to put into this.