I have a Windows Form application with a basic grid of data. I have enabled row filtering via the header icon.
My user has asked if I can add a button to the top of each column which allows them to copy the contents of the cell in the first row of that column to all the other cells in that column, and I'm trying to figure out the best way to accomplish this.
Can I add a custom button to a column header and create an event handler for it?
Or can I override the event hanlder for one of the other existing column header buttons?
Or can I freeze the first row so that it is unaffected by scrolling/filtering and add buttons to the cells in this row?
I guess the real question is "What is the best way to accomplish what I'm trying to do?"
Thanks so much!
Steve
Hi Steve,
Almost any of these would work. The cleanest solution would be the first one.
sweeks said:Can I add a custom button to a column header and create an event handler for it?
To do this, you would use a CreationFilter. CreationFilter's have a bit of a learning curve and they can be a bit daunting if you haven't used them before, but they are incredibly powerful tools and learning them is worth your while.
Using a CreationFilter, you could add a ButtonUIElement into the HeaderUIElement and adjust the other UIElements within the header to make room for it.
If you want to explore CreationFilters, I recomend that you search the Infragistics Knowledge Base for CreationFilter and you will find lots of sample - some of which may be pretty similar to what you want to do. Also, I strongly recommend that you get the Infragistics UIElementViewer Utility. It's very useful when dealing with UIElements.
If you don't want to go that route, then the next best thing would be:
sweeks said:Or can I freeze the first row so that it is unaffected by scrolling/filtering and add buttons to the cells in this row?
You can fix a row in the grid by simply setting the Fixed property on the row. You could loop through the cells in the row and set the Style on each cell to Button.
Also, the row will still be filtered out as normal. So you would need to handle the FilterRow event of the grid and prevent this row from being filtered.
Thanks Mike. I've been studying the Creation Filter and I think I have a VERY high level understanding of it as follows:
1. I create a Creation Filter2. I create a custom UI Element based on an existing one (image and button)3. I attach the creation filter to an Element on my form (ultrawingrid)4. In the Creation Filter, I add logic that will place the custom UI Element (button) in the element on my form(grid column header)
I apologize for bugging you, but I'm excited to get this working, and had a few more questions. I couldn't find any examples in the knowledge base that were specific to adding somthing to a column header.
Questions:
1. Do a attach the CreationFilter to the grid (i.e. mygrid.CreationFilter = myCreationFilter), or do I somehow attach it directly to column headers? My assumption is that I attach it to the grid, and that the Creation Filter logic will discern whether or not the UIElement is a column header and either add the button or not.
2. If my assumption is correct, what is the element the Creation Filter should be looking for which represents a coumn header? In debug mode, I've watched many elements come across but none of them appeared to be a column header. I've been able to add my button to various random places on the grid, but not in the column headers yet.
Thanks so much Mike!
sweeks said:I apologize for bugging you, but I'm excited to get this working, and had a few more questions. I couldn't find any examples in the knowledge base that were specific to adding somthing to a column header.
No problem. Your enthuiasm is infectious. :)
sweeks said:1. Do a attach the CreationFilter to the grid (i.e. mygrid.CreationFilter = myCreationFilter), or do I somehow attach it directly to column headers? My assumption is that I attach it to the grid, and that the Creation Filter logic will discern whether or not the UIElement is a column header and either add the button or not.
You are correct. You attach your CreationFilter to the grid via the grid.CreationFilter property. There are two methods on the IUIElementCreationFilter interface. BeforeCreateChildElements and AfterCreateChildElements. In your case, you would just return false from the Before so it does nothing. You need to use the After because you need to move the existing child elements out of the way to make room for your button.
sweeks said:2. If my assumption is correct, what is the element the Creation Filter should be looking for which represents a coumn header? In debug mode, I've watched many elements come across but none of them appeared to be a column header. I've been able to add my button to various random places on the grid, but not in the column headers yet.
This is where the Infragistics UIElementViewer Utility would be particularly handy. This utility will allow you to move your mouse over the grid and see the UIElements that exist at any given point. I strongly advise you to do this, because this will let you see the existing elements and their children so you will have a clear mental picture of what element you need to look for and what child elements you will need to move around in order to make room for your button.
Off the top of my head, the element you are looking for here is probably the HeaderUIElement. I think this element has a Header property, so you can check to see if the Header is a ColumnHeader and if so, get the Column from that.
Hi,
I have this code for the Button on header thing:
aButtonUIElement =
new ButtonUIElement(parent);
}
aTextUIElement = (
TextUIElement)parent.GetDescendant(typeof(TextUIElement));
Infragistics.Win.UltraWinGrid.
ColumnHeader aColumnHeader =(Infragistics.Win.UltraWinGrid.ColumnHeader)aButtonUIElement.GetAncestor(typeof(HeaderUIElement
)).GetContext(typeof(Infragistics.Win.UltraWinGrid.ColumnHeader));
aButtonUIElement.ElementClick +=
new UIElementEventHandler(aButtonUIElement_ElementClick);
parent.ChildElements.Add(aButtonUIElement);
aButtonUIElement.Rect =
new Rectangle(parent.Rect.X + 3, parent.Rect.Y + ((parent.Rect.Height - aButtonUIElement.TextRect.Height) / 2), aButtonUIElement.TextRect.Width, aButtonUIElement.TextRect.Height);
aTextUIElement.Rect =
new Rectangle(aButtonUIElement.Rect.Right + 3, aTextUIElement.Rect.Y, parent.Rect.Width - (aButtonUIElement.Rect.Right - parent.Rect.X), aTextUIElement.Rect.Height);
Strangely, the ElementClick, never gets triggered. Can you help out? May be give me the code that worked for your button on header?
Thank you,
Karthik.
I was sucessfully able to use the CalculateAutoResizeWidth to account for my new button. I think I'll just disable manual resizing (they shouldn't have to anyway). So all is well, and my questions are answered. Thanks again for all you help Mike!
Unfortunately, there's no way the grid can know about your button when autosizing the column.
If you are calling PeformAutoResize on the column in code, then what you can do is call CalculateAutoResizeWidth, instead. Then you can simply add in the width of your button and set the Width of the column to the total width.
If the user double-clicks on the right edge of the column header, there's really not muh you can do there. You could trap the BeforeColResize event, but there's no way to tell inside this event if the column is being automatically resized or just sized by a drag and drop.
Thanks a million Mike! This worked. Inow have my buttons on the headers I want and am able to manipulate the contents of the columns when the button is clicked. I really appreciate your help.
I wasn't able to get the Viewer working, but I'm going to try again. It sounds like an awesome utility for this sort of thing. Better than my method of setting break points and looking at "element.Parent.Parent.Parent" etc. :)
One last related thing. When I place the button in the header using the Rect property, I am setting its x value to be 40 from the right inside border. This puts it just to the left of the sort indicator in the header, but obviously the button is not taken into account when I autoresize either programatically or manually by double clicking the header border.
Is there a good way to place the button in the header so that it is taken into account in an autoresize so that it won't display overlaid on the header caption?
Thanks again,