There is no single solution.
1. This has nothing to do with 7.5.2....it's all ActiveX grids since their inception in SLX. we just haven't tested the grids with THOUSANDS of rows. Even 1500 rows is reasonably fast.....but go to 2,000 plus and CPU spikes at 100% with no memory increase (despite plenty of available RAM).
2. It has everything to do with vbscript object typing versus integer typing (FOR EACH vs FOR I when traversing a selection collection).
3. It has everything to do with server side sorts with SECCODE and Field Level Security checks through the SLX OLE DB Provider versus client side record set sorts. That means trapping user caption click/header click sorting prior to SLX sorting on the server.
4. Sortable must be true for proper selection collection adds and traversing the collection (processing). If it is false or VSSC is employed then all bets are OFF. Test Grid.Selection.Count vs Grid.SelectedNodes.Count if you want the skinny.
Solutions to both are being worked on as this is being posted.....with the sort working DARN WELL at this point.
Here's some food for thought.
and look at the other posts I've made on this (see CONTROLS forum).
Sub DataGrid1MouseDown(Sender, Button, X, Y) ' ** For Developer Reference ** ' Sender.GetHitInfo(X,Y).HitType apparent values: ' 1 : ColumnHeader - A Column Header in the DataGrid control. will sort on MouseUp if X, Y are unchanged. ' 1 : ColumnHeader - Column Move - The column itself is clicked (Mouse Down HitType = 1). ' The column can be dragged to another position (a move). ' On mouse up hit the type CAN BE a 2. colindex remains unchanged. X MUST change (and maybe Y)!. ' N/A : ' 1 : ColumnHeader - A Column Header in the DataGrid control. will not sort on a move (mouse up hittype = 2). ' 2 : ColumnHeader. Registered a hit type of 2 on a MOUSE UP ONLY. this is a Column resize OR move, no sort. ' Column Resize - The column border, which is the line between column headers. It can be dragged to resize a column's width. ' or the column can be moved. Their is no mouse down hit type, mouse up hit type is a 2. ' Column Move - The column itself is clicked (Mouse Down HitType = 1). ' The column can be dragged to another position (a move). ' mouse up hit type CAN BE a 2. colindex remains unchanged. X changes!. ' 3 : +- button on a grouped grid row title/bar (Expand, Contract Group) ' 8 : None - The background area, visible when the control contains no table, few rows, or when a table is scrolled to its bottom.
' 7: Cell - A cell in the DataGrid control if RowSelect = False ' use event DataGrid1Editing(Sender, PrimaryKeyValue, FieldName, Value) ' to determine current cell clicked upon. ' 7: Row - A cell in the DataGrid control if RowSelect = True ' ? : Caption - The caption of the DataGrid control. ' 10: Group column header (section or control) of the DataGrid control. ' 18: Summary Footer section of the DataGrid control. ' ' ? : RowHeader - A row header in the System.Windows.Forms.DataGrid control. ' ? : RowResize - The row border, which is the line between grid row headers. It can be dragged to resize a row's height. ' DataGrid1.GetCurrentFieldValue() ' currently selected Row's KeyFieldValue (see grid control KeyField property). ' DataGrid1.GetFieldValue KeyFieldValue, "FieldOrColumnName" ' DataGrid1.HWND A Console Window Handle. Long integer pointer to the Windows Handle ' A window handle (usually shortened to hWnd) is a unique identifer that Windows assigns to each window created. By window in this case we are referring to everything from command buttons and textboxes, to dialog boxes and full windows. ' The window handle is used in APIs as the sole method of identifying a window. It is a Long (4 byte) value and you can get the handle for forms and almost all controls in Visual Basic by using the .hWnd property.
' AutoSort should be set to False prior to grid data being filled. This prevents user sorts on the grid. ' ' If you fire off the Sort based on the mouse down event handler, hittype = 1 ' Two 'errors' come into play: ' 1. Column Moving cannot be invoked. ' 2. Grouping sort direction cannot be changed.
' Proposed Solution to Column Moving: ' During Mouse Down event: Trap the X, Y, HitType and Grid Name. ' During Mouse Up event: IF the X, Y, HitType and Grid Name are the SAME and HitType = 1 Then the USer wants to Sort. ' If the X, Y, or hittype are different, then the user was selecting other rows, moving a column, resizing a grid column. ' (the ctrl or shift keys, et al may have been clicked by the user....or a scroll button on the mouse). ' If the grid names are different then we're working on a different grid. ' ONLY a mouse down with an unchanged position mouse up (a Click!) on the same grid's grid header means sort. ' run the grid sort routine.
Dim msg
' Due to uncertainty over the Sender.GetHitInfo, set On Error command to handle unpredicted situations. On Error Resume Next
currentGridX = X currentGridY = Y
' get Column index of what column the user clicked upon. currentGridColIndex = Sender.GetHitInfo (currentGridX,currentGridY).Column.Index
' Get hit type. 1 is a column\caption header. currentGridMouseDownHitType = Sender.GetHitInfo (currentGridX,currentGridY).HitType
msg = "Mouse Down" & _ " ColIndex:= " & currentGridColIndex & _ " HitType:= " & currentGridMouseDownHitType & _ " Button Used:= " & Button & _ " X:Y= (" & currentGridX & ":" & currentGridY & ")" application.Debug.WriteLine "SLX " & msg
' 2/3/2010 RJS Do this on the MouseUp instead. ' Call GridCommon_MouseDownEventHandler (Sender, Button, X, Y) ' 2/4/2010 RJS: use this to capture the user's sort desires, but not actually sort. ' SetSortGlyphMouseDown (byRef theGrid, byVal theSortColIndex) If currentGridMouseDownHitType = 1 Then Call SetSortGlyphMouseDown (Sender, currentGridColIndex ) application.Debug.WriteLine "SLX SetSortGlyphMouseDown " & " Potential Sort! AutoSort is " & SENDER.AutoSort & " Sortable is " & Sender.Sortable End If
' This gives the count of visible to the user rows that have been selected. Usually 1. ' if the user clicks on the grid but not on a cell/row this is 0. ' if the user drags a column header up to the group panel, this is the count of Parent Nodes. currentGridMDSelectedNodesCount = sender.SelectedNodes.Count lblMDSelectionCount.Caption = "MD Selected: " & currentGridMDSelectedNodesCount & " rows. "
Call GetSetSelectionCount(Sender)
PriorGridX = X PriorGridY = Y PriorGridHitType = currentGridMouseDownHitType
If Sender.Sortable Then cbSortable.Text = "T" Else cbSortable.Text = "F" End If
' Reset On Error command On Error GoTo 0 End Sub
Sub DataGrid1MouseUp(Sender, Button, X, Y) Dim MSG currentGridX = X currentGridY = Y
' Get hit type. 1 is a column\caption header. currentGridMouseUpHitType = Sender.GetHitInfo (currentGridX,currentGridY).HitType msg = "Mouse Up " & _ " ColIndex:= " & currentGridColIndex & _ " HitType:= " & currentGridMouseUpHitType & _ " Button Used:= " & Button & _ " X:Y= (" & currentGridX & ":" & currentGridY & ")" & _ " Old X:Y= (" & PriorGridX & ":" & PriorGridY & ")"
If ((PriorGridX = X) AND _ (PriorGridY = Y) AND _ (PriorGridHitType = currentGridMouseUpHitType) AND _ (currentGridMouseUpHitType = 1) ) Then ' this is a sort. PotentialGridSort = True application.Debug.WriteLine "SLX " & msg & " *** Sorting! " Call MouseUpEventHandler (Sender, Button, X, Y, PotentialGridSort) PriorGridSortIndex = CurrentGridSortIndex PriorGridSortDirection = CurrentGridSortDirection Else PotentialGridSort = False application.Debug.WriteLine "SLX " & msg End If
' Call MouseUpEventHandler (Sender, Button, X, Y, PotentialGridSort)
' This gives the count of visible to the user rows that have been selected. ' A Mouse down with the shift key down doesn't count as a mouse up when you navigate to another cell/row. ' if you mouse down on row 1 with the shift key down, then the mouse up event will return the number of visible nodes selected. ' Maximum count is the visible grid rows without scrolling. ' if the user clicks on the grid but not on a cell/row this is 0.
currentGridMUSelectedNodesCount = sender.SelectedNodes.Count lblMUSelectionCount.Caption = "MU Selected: " & currentGridMUSelectedNodesCount & " rows. "
Call GetSetSelectionCount(Sender)
PriorGridX = X PriorGridY = Y End Sub
Sub DataGrid1RowSelect(Sender)
End Sub
SUB GetSetSelectionCount(TheGrid) With TheGrid currentGridSelectionCount = .Selection.Count If (currentGridMUSelectedNodesCount > 0 OR currentGridMDSelectedNodesCount > 0) AND currentGridSelectionCount > 0 Then Else currentGridSelectionCount = 0 End If lblSelectionCount.Caption = "Selected Rows: " & currentGridSelectionCount End With End Sub
5. Sorting grids fast means using Grid.RecordSet.SORT instead of letting vbscript/SLX run Another server side select statement on the data you already have... and yet another test for both SECCODE row acquisition and FLS cell security. I'm sure server side sorts (ORDER BY) might be faster in some horribly complex joined and large recordsets. But we solve all of that by using server side record set fills of the grid (we literally never use grid.SQL.TEXT!) and then sort by recordset (grid.recordset.SORT "ACCOUNT Asc" kinds of stuff).
'************************************************************** ' Name: GridCommon_SortGridbyRS ' Purpose: Sort the data display in a Grid control by ' first sorting a recordset and then placing ' that RS into the grid. ' Assumptions: The grid column object clicked on has the current sort properties for the column to be sorted. ' Effects: Client Side memory sort of an ADO Record Set (RS.SORT), sorted on the provided Sort Column Idex. ' If previous click on this column was no sort or Descending sort, then the sort will be Ascending. ' If previous click on this column was a Ascending Sort, then the sort will be Descending. ' Inputs: by Reference theGrid - Grid control itself ' by Referehce theRS - the ADO Recordset to put into Grid ' TheSortColIndex - integer - the column to be sorted. ' Returns: ' Dev Notes: Calls the RefreshGridByRS subroutine to ' refresh the grid. '************************************************************** ' 1/28/2010 EB: Removed the ByRef TheRS paramter as it is no longer used. Sorting is now achieved ' through the grid recordset. Sub GridCommon_SortGridbyRS(byRef theGrid, byVal theSortColIndex) ' Sort the recordset based on the grid column index provided. ' Test to see if the column has already been sorted (i.e. the currently sorted column name is in the RS sort property). ' If the same column was the last sort, then reverse sort direction Asc/ Desc.
DIM sortFieldName DIM lastRSsort DIM sortString DIM incomingSortableValue
' Turn sortable off if True. Record the original value so that it can be reset after the sort (if it came in as True). If theGrid.Sortable = True Then incomingSortableValue = True theGrid.Sortable = False Else incomingSortableValue = False End If
' Set the On Error command to handle exceptions where a required object does not exist. 'On Error Resume Next
' Get the Fieldname for the Column Index provided sortFieldName = theGrid.Columns.Item(theSortColIndex).FieldName
' Get value for previous sort (if exists), expected format: FIELDNAME Asc / FIELDNAME Desc ' 1/28/2010 EB: Replaced reference to theRS with theGrid.Recordset lastRSsort = "" & theGrid.Recordset.Sort
' Test if same column as previous sort? If InStr(lastRSsort, sortFieldName) Then ' Test if previous sort was Ascending If InStr(lastRSsort, "Asc") Then ' Set current sort to Descending sortString = sortFieldName & " Desc" Else ' Previous sort was Descending, set current sort to Ascending sortString = sortFieldName & " Asc" End If Else ' Not the same solumn as previous sort, set current sort to Ascending sortString = sortFieldName & " Asc" End If
' Sort the recordset based on the sortString ' 1/28/2010 EB: Sort the Grid.Recordset in place of the old theRS recordset object. 'theRS.Sort = sortString theGrid.Recordset.Sort = sortString
' Refresh the grid so that the newly sorted data is displayed. ' 1/28/2010 EB: As we are no longer sorting a seperate recordset for sorting ' refresh is achieved by passing the in grid recordset. 'GridCommon_RefreshGridByRS theGrid, theRS Set theGrid = theGrid.Recordset
' If sortable was set to True when the sub was called, then turn it back on. If incomingSortableValue = True Then theGrid.Sortable = True End If
' Reset On Error command 'On Error GoTo 0 End Sub
|