Hi, I have a question about the group caption in WinGrid.
The caption in group column header can only be aligned to the left of the group. When users are scrolling horizontally, the caption can't be show on the screen. Is there anyway to keep the caption floating?
Please see attached screenshot. On the second image, the caption 'AGLPA' is lost.
Thanks.
Regards,
Jason
Hi Jason,
If you want to keep the group header in view at all times, then you'd have to use a CreationFilter. There's no property setting for this.
If you have not worked with CreationFilters before, they can be a bit daunting, but they are well worth the effort they take to learn because they are so powerful.
This one is a bit tricky. What you have to do is make sure the TextUIElement that is inside the HeaderUIElement for the group doesn't span the entire width of the HeaderUIElement (which gets scrolled off-screen), but is instead limited by the visible area of the grid. And you would have to do this for both the left and the right.
And just to make this even more complicated, you would have to refresh the elements any time the grid scrolls.
Here's some quick sample code I whipped up which seems to work okay, although I didn't test it very thoroughly:
public class MyCreationFilter : IUIElementCreationFilter { #region IUIElementCreationFilter Members void IUIElementCreationFilter.AfterCreateChildElements(UIElement parent) { HeaderUIElement headerUIElement = parent as HeaderUIElement; if (headerUIElement != null && headerUIElement.Header != null && headerUIElement.Header.Group != null) { UIElement textUIElement = parent.GetDescendant(typeof(TextUIElement)); UIElement rowColRegionIntersectionUIElement = parent.GetAncestor(typeof(RowColRegionIntersectionUIElement)); if (textUIElement != null && rowColRegionIntersectionUIElement != null) { int newLeft = rowColRegionIntersectionUIElement.Rect.Left; if (newLeft > textUIElement.Rect.Left) { int newWidth = textUIElement.Rect.Width - (newLeft - textUIElement.Rect.Left); textUIElement.Rect = new Rectangle( newLeft, textUIElement.Rect.Top, newWidth, textUIElement.Rect.Height); textUIElement.Invalidate(); } else { int newRight = rowColRegionIntersectionUIElement.Rect.Right; if (newRight < textUIElement.Rect.Right) { int newWidth = textUIElement.Rect.Width - (textUIElement.Rect.Right - newRight); textUIElement.Rect = new Rectangle( textUIElement.Rect.Left, textUIElement.Rect.Top, newWidth, textUIElement.Rect.Height); textUIElement.Invalidate(); } } } } } bool IUIElementCreationFilter.BeforeCreateChildElements(UIElement parent) { // Do nothing return false; } #endregion }
Hi Mike,
Thanks for your code. This works perfect in a normal scenario. But this seems not working when I have the first column group pinned (fixed).
Yes, my sample code is not accounting for fixed groups. In order to do that, you would have to account for the right edge of the last fixed group in addition to bounding by the Rect of the BandHeadersUIElement like I did here.
One way to do this would be to loop through all of the ChildElements in the BandHeadersUIElement. For each HeaderUIElement whose group is not null, you would get the group and see if it's fixed and if so, use it's Rect.Right to set the newLeft variable - assuming the right was higher.
Another, slightly more robust option, is to use the Region of the HeaderUIElement to determine the bounding rect. This second method is better, because it's using the grid's own clipping data. So in theory, it may handle other cases (although I can't actually think of any at the moment). The down side is that, in order to get the rect from the region, you need a Graphics object, so the CreationFilter will need a reference to the grid. So that means you cannot use the same instance of the CreationFilter for multiple grids - you will need a new instance for each grid.
Here's some updated code using this second (more reliable) approach.
public class MyCreationFilter : IUIElementCreationFilter { UltraGrid grid; public MyCreationFilter(UltraGrid grid) { this.grid = grid; } #region IUIElementCreationFilter Members void IUIElementCreationFilter.AfterCreateChildElements(UIElement parent) { HeaderUIElement headerUIElement = parent as HeaderUIElement; if (headerUIElement != null && headerUIElement.Header != null && headerUIElement.Header.Group != null) { UIElement bandHeadersUIElement = parent.GetAncestor(typeof(BandHeadersUIElement)); UIElement textUIElement = parent.GetDescendant(typeof(TextUIElement)); if (textUIElement != null && bandHeadersUIElement != null) { Rectangle boundingRect = headerUIElement.Rect; if (headerUIElement.Region != null) { Graphics g = DrawUtility.GetCachedGraphics(this.grid); try { boundingRect = Rectangle.Ceiling(headerUIElement.Region.GetBounds(g)); } finally { DrawUtility.ReleaseCachedGraphics(g); } } boundingRect = Rectangle.Intersect(boundingRect, bandHeadersUIElement.Rect); int newLeft = boundingRect.Left; if (newLeft > textUIElement.Rect.Left) { int newWidth = textUIElement.Rect.Width - (newLeft - textUIElement.Rect.Left); textUIElement.Rect = new Rectangle( newLeft, textUIElement.Rect.Top, newWidth, textUIElement.Rect.Height); textUIElement.Invalidate(); } else { int newRight = boundingRect.Right; if (newRight < textUIElement.Rect.Right) { int newWidth = textUIElement.Rect.Width - (textUIElement.Rect.Right - newRight); textUIElement.Rect = new Rectangle( textUIElement.Rect.Left, textUIElement.Rect.Top, newWidth, textUIElement.Rect.Height); textUIElement.Invalidate(); } } } } } bool IUIElementCreationFilter.BeforeCreateChildElements(UIElement parent) { // Do nothing return false; } #endregion }