Hi and thanks for reading my question,
I have a UltraWinGrid with a large number of rows, let's say more than 100. On the screen at a given time there are visible only about 7, 8 of them. I'm looking for a way of showing only the rows that are fully visible, so if the last row is not completely visible it should not be visible until the grid is scrolled.
I've searched for a property or for a method of doing this. It can easily be done for columns but i haven't found a way to do it for rows. Also in this case resizing the grid is not an option.
Thanks for any tips,
Adrian Faciu.
Hi Adrian,
So basically, you don't want the grid to show any partially-visible rows?
You would have to use a CreationFilter for this. Here's some quick code I whipped up which seems to work pretty well:
public class HidePartialRows_CreationFilter : IUIElementCreationFilter { #region IUIElementCreationFilter Members void IUIElementCreationFilter.AfterCreateChildElements(UIElement parent) { // Check for the RowColRegionIntersectionUIElement. This is the element // that contains the RowUIElements (and possibly other things). if (parent is RowColRegionIntersectionUIElement) { // Keep a list of elements that we want to remove. We will probably // only have one element in the list, but it doesn't hurt to be extra careful. List<UIElement> elementsToRemove = new List<UIElement>(); // Loop through the child elements. foreach (UIElement element in parent.ChildElements) { // Check for RowUIElements. We don't care about any other type here, // so if it's not a RowUIElement, skip it. RowUIElement rowUIElement = element as RowUIElement; if (rowUIElement == null) continue; // Check to see if the RowUIElement extends beyond the bottom of the parent. if (rowUIElement.Rect.Bottom > parent.Rect.Bottom) { // This Row is clipped, so add it to the list of elements to remove. // We don't want to remove the element here directly, because that // would modify the contents of the ChildElements collection, and we // are currently in a ForEach loop on that collection so it's a bad idea. elementsToRemove.Add(element); } } // Remove all of the elements we marked for removal. foreach (UIElement element in elementsToRemove) { parent.ChildElements.Remove(element); } } } // Do nothing bool IUIElementCreationFilter.BeforeCreateChildElements(UIElement parent) { return false; } #endregion }
Mike it's really helpful code. i am able to remove last partial row but still i have an issue last visible row when i am trying to click on it , it steps up and put focus on next one. is there any way i can hide last two rows one is partial visible and one visible?
Mike,
Thanks for your reply.
As you mentioned I comment this lines of code and now only last partial visible row is not visible. Thanks for your help. but we are using this code to create a header checkbox to select all rows in grid. So now when I comment this code I am not able to create header checkbox. Can you please let me know which line in this code has issue?
If TypeOf parent Is HeaderUIElement Then
' ' Get the actual ColumnHeader that the HeaderUIElement is attached to
' Dim aColHeader As ColumnHeader
' aColHeader = CType(parent, HeaderUIElement).Header
' ' Only put the Checkbox in the header of the Boolean columns
' If aColHeader.Column.Key = oKey Then
' Dim aTextUIElement As TextUIElement
' Dim aCheckBoxUIElement As CheckBoxUIElement
' ' Since the grid sometimes re-uses UIElements, we need to check to make sure
' ' the header does not already have a CheckBoxUIElement attached to it.
' ' If it does, we just get a reference to the existing CheckBoxUIElement,
' ' and reset its properties.
' aCheckBoxUIElement = parent.GetDescendant(GetType(CheckBoxUIElement))
' If aCheckBoxUIElement Is Nothing Then
' ' Create a New CheckBoxUIElement
' aCheckBoxUIElement = New CheckBoxUIElement(parent)
' End If
' ' Get the TextUIElement - this is where the text for the
' ' Header is displayed. We need this so we can push it to the right
' ' in order to make room for the CheckBox
' aTextUIElement = CType(parent.GetDescendant(GetType(TextUIElement)), TextUIElement)
' ' Sanity check
' If aTextUIElement Is Nothing Then Exit Sub
' ' Get the Header and see if the Tag has been set. I the Tag is
' ' set, we will assume it's the stored CheckState. This has to be
' ' done in order to maintain the CheckState when the grid repaints and
' ' UIElement are destroyed and recreated.
' Dim aHeader As ColumnHeader = CType(aCheckBoxUIElement.GetAncestor(GetType(HeaderUIElement)).GetContext(GetType(ColumnHeader)), ColumnHeader)
' If aHeader.Tag Is Nothing Then
' ' If the tag was nothing, this is probably the first time this
' ' HeaderRow is being displayed, so default to Indeterminate
' 'aHeader.Tag = Windows.Forms.CheckState.Indeterminate
' If oCheckState Then
' aHeader.Tag = Windows.Forms.CheckState.Indeterminate
' Else
' aHeader.Tag = oCheckState
' aCheckBoxUIElement.CheckState = CType(aHeader.Tag, Windows.Forms.CheckState)
' ' Hook the ElementClick of the CheckBoxUIElement
' AddHandler aCheckBoxUIElement.ElementClick, AddressOf aCheckBoxUIElement_ElementClick
' ' Add the CheckBoxUIElement to the HeaderUIElement
' parent.ChildElements.Add(aCheckBoxUIElement)
' ' Position the CheckBoxUIElement. The number 3 here is used for 3
' ' pixels of padding between the CheckBox and the side of the header
' ' The CheckBox is shifted down slightly so it is centered in the header
' aCheckBoxUIElement.Rect = New System.Drawing.Rectangle(parent.Rect.X + 6, parent.Rect.Y + ((parent.Rect.Height - aCheckBoxUIElement.CheckSize.Height) / 2), aCheckBoxUIElement.CheckSize.Width, aCheckBoxUIElement.CheckSize.Height)
' ' Push the TextUIElement to the right a little to make
' ' room for the CheckBox. 3 pixels of padding are used again.
' aTextUIElement.Rect = New System.Drawing.Rectangle(aCheckBoxUIElement.Rect.Right + 3, aTextUIElement.Rect.Y, parent.Rect.Width - (aCheckBoxUIElement.Rect.Right - parent.Rect.X), aTextUIElement.Rect.Height)
' ' If the column is not a boolean column, we do not want to have a checkbox in it
' ' Since UIElements can be reused by the grid, there is a chance that one of the
' ' HeaderUIElements that we added a checkbox to for a boolean column header
' ' will be reused in a column that is not boolean. In this case, we must remove
' ' the checkbox so that it will not appear in an inappropriate column header.
' If Not aCheckBoxUIElement Is Nothing Then
' parent.ChildElements.Remove(aCheckBoxUIElement)
' aCheckBoxUIElement.Dispose()
End If
Hi mike, I found issue but the thing is now when I make last partial row invisible at that time that portion is empty which really looks dirty.
Is there any way I can handle that area?
Is there a way I can expand last row which is fully visible to cover that area?
It might be possible, but it would be tricky. You could try setting the height of the row. But you would have to determine the correct height, which is no simple task, You would also have to set RowSizing to free to allow variable-height rows.
Another option might be to change the height of the RowUIElement with your creation filter, but I don't think that will work unless you also change the height of all the child elements, and there are quite a few, so it would be difficult to account for the all.
Also... do you know that the latest version of the grid has header checkbox functionality built-in? So you don't need a creation filter for that, any more.
Thanks Mike. So you mean that in current latest version we have a header checkbox functionality?
Can you please give me a sample code to see that how to set height of row or Row element?
OK let me think for a button or message.
But still issue is that even when i click last fully visible row as was attached in screenshot still it moves up.
Yes, that was the point of my sample code - since the partial row is not visible, it alleviates the problem with clicking on that row and having it scroll into view. You have to explicitly scroll the row into view and then click it, so there's no weird mouse behavior, like clicking on a row and having that row move so that there's a different row under the mouse when you release the mouse button.
It looks like maybe Georgi's code was intended to stretch the last fully-visible row so that it fills the available space. Seems like a bizarre UI to me, but it that's what you want you could extend the UIElements in the last visible row. You can't change the Height property on the row inside a CreationFilter - that's a bad idea.
Another option would be to create some other element and put it into that gap - like a message or a button that you could click to scroll the next row into view. But that's problematic, because the height of the gap can vary and there might not be enough room for any other elements.
This sample project was given by Georgi to set height of row. now i am using a code which is given by you.
I attach a screenshot how it looks.
The last partial visible row is hidden but it's a blank row over there means there is noting in that area.
Hi,
The code you are using in this sample isn't anything like the code I posted. One big problem with this code is that you are setting the Height property on the row inside of the CreationFilter. You should not do that, as this will dirty the grid elements and cause the CreationFilter to fire again in an infinite loop.
The code I posted just hides the last row if it is cut off. Why are you resizing the rows?
Here is your sample where i made this change.
(rowUIElement.Rect.Bottom >= parent.Rect.Bottom)
You can see now how it behaves.