Displaying SortIndicators on the Left side of the column header

Posted by: j2associates on 8 September 2017, 1:25 pm EST

  • Posted 8 September 2017, 1:25 pm EST

    Hello all,


    Is there any way to display the column sort indicator on the left side of the column header instead of on the right? We have a spread with a path column that can get very long. We typically do not display it all, but it needs to be flagged sortable. Thanks in advance for any ideas and/or suggestions!

  • Replied 8 September 2017, 1:25 pm EST

    Hello all,


    A followup question, how do I override the hit test? Even the the Text is properly moved to the right, it still sorts if clicking on the right side where the sort indicator is normally displayed. Thanks in advance for any ideas and/or suggestions!

  • Replied 8 September 2017, 1:25 pm EST

    Hello all,


    Based upon some example code posted by ScottS in the link above, I created the following ColumnHeaderRendererEx class. The problem is that the SortIndicator is not painted. As can be seen from the attached jpeg, the Text is moved over correctly and leaves room for the SortIndicator but it does not paint.



    Public Class EnhancedColumnHeaderRendererEx
        Inherits CellType.EnhancedColumnHeaderRenderer


        Public Enum SortIndicatorPositions As Integer
            [Default] = 0
            Left
            Right
        End Enum 'SortIndicatorPositions


        Private Const m_SORT_INDICATOR_WIDTH As Integer = 16


    #Region " << Constructors >> "


        Public Sub New()
            MyBase.New()
        End Sub 'New


        Public Sub New(ByVal sortIndicatorPosition As SortIndicatorPositions)
            MyClass.New()
            Me.SortIndicatorPosition = sortIndicatorPosition
        End Sub 'New


    #End Region


    #Region " << SortIndicatorPosition >> "


        Private m_SortIndicatorPosition As SortIndicatorPositions = GetDefaultSortIndicatorPosition()
        Public Property SortIndicatorPosition() As SortIndicatorPositions
            Get
                Return m_SortIndicatorPosition
            End Get
            Set(ByVal value As SortIndicatorPositions)
                m_SortIndicatorPosition = value
            End Set
        End Property 'SortIndicatorPosition


        Private Function GetDefaultSortIndicatorPosition() As SortIndicatorPositions
            Try
                Return SortIndicatorPositions.Default
            Catch ex As Exception
                Throw
            End Try
        End Function 'GetDefaultSortIndicatorPosition


        Public Sub ResetSortIndicatorPosition()
            GetDefaultSortIndicatorPosition()
        End Sub 'ResetSortIndicatorPosition


    #End Region


        Public Overrides Sub PaintHeader(ByVal g As System.Drawing.Graphics, ByVal r As System.Drawing.Rectangle, ByVal rectTextIn As System.Drawing.Rectangle, ByVal backColor As System.Drawing.Color, ByVal foreColor As System.Drawing.Color, ByVal font As System.Drawing.Font, ByVal halign As FarPoint.Win.HorizontalAlignment, ByVal valign As FarPoint.Win.VerticalAlignment, ByVal pressed As Boolean, ByVal focus As Boolean, ByVal text As String, ByVal textDown As String, ByVal nAlign As FarPoint.Win.ButtonTextAlign, ByVal textOrientation As FarPoint.Win.TextOrientation, ByVal wordWrap As Boolean, ByVal shadowSize As Integer, ByVal darkColor As System.Drawing.Color, ByVal lightColor As System.Drawing.Color, ByVal pictUp As System.Drawing.Image, ByVal pictDown As System.Drawing.Image, ByVal bLocked As Boolean, ByVal prefix As System.Drawing.Text.HotkeyPrefix, ByVal style As FarPoint.Win.VisualStyles, ByVal mouseOver As Boolean, ByVal rightToLeft As Boolean, ByVal appearance As FarPoint.Win.Spread.Appearance, ByVal textRotationAngle As Double)
            Try
                Dim location As Rectangle
                Select Case Me.SortIndicatorPosition
                    Case SortIndicatorPositions.Default, SortIndicatorPositions.Right
                        MyBase.PaintHeader(g, r, rectTextIn, backColor, foreColor, font, halign, valign, pressed, focus, text, textDown, nAlign, textOrientation, wordWrap, shadowSize, darkColor, lightColor, pictUp, pictDown, bLocked, prefix, style, mouseOver, rightToLeft, appearance, textRotationAngle)
                        location = rectTextIn


                    Case SortIndicatorPositions.Left
                        Dim newLocation As Rectangle
                        With rectTextIn
                            newLocation = New Rectangle(New Point(.X + m_SORT_INDICATOR_WIDTH, .Y), New Size(.Width, .Height))
                        End With
                        MyBase.PaintHeader(g, r, newLocation, backColor, foreColor, font, halign, valign, pressed, focus, text, textDown, nAlign, textOrientation, wordWrap, shadowSize, darkColor, lightColor, pictUp, pictDown, bLocked, prefix, style, mouseOver, rightToLeft, appearance, textRotationAngle)
                        location = newLocation


                    Case Else
                        Throw New ArgumentException([String].Format("Unexpected SortIndicatorPosition '{0}'.", Me.SortIndicatorPosition))
                End Select


                Debug.WriteLine("")
                Debug.WriteLine([String].Format("{0} r: {1}{2}rectTextIn: {3}", vbTab & vbTab, r, vbNewLine, location))
            Catch ex As Exception
                Throw
            End Try
        End Sub 'PaintHeader


        Public Overrides Sub PaintSortIndicator(ByVal g As System.Drawing.Graphics, ByVal r As System.Drawing.Rectangle, ByVal appearance As FarPoint.Win.Spread.Appearance, ByVal zoomFactor As Single)
            Try
                Dim location As Rectangle
                Select Case Me.SortIndicatorPosition
                    Case SortIndicatorPositions.Default, SortIndicatorPositions.Right
                        MyBase.PaintSortIndicator(g, r, appearance, zoomFactor)
                        location = r


                    Case SortIndicatorPositions.Left
                        Dim newLocation As Rectangle
                        With r
                            newLocation = New Rectangle(New Point(0, .Y), New Size(.Width, .Height))
                        End With
                        MyBase.PaintSortIndicator(g, newLocation, appearance, zoomFactor)
                        location = newLocation
                End Select


                Debug.WriteLine([String].Format("PaintSortIndicator r: {0}", location))
            Catch ex As Exception
                Throw
            End Try
        End Sub 'PaintSortIndicator


    End Class 'EnhancedColumnHeaderRendererEx


     



  • Replied 8 September 2017, 1:25 pm EST


    Hello,


    Sorry, I found an earlier thread that gets me started - Customizing sort indicators: http://www.clubfarpoint.com/Forums/forums/thread/62099.aspx.

  • Replied 8 September 2017, 1:25 pm EST

    Thanks ScottS! The sort indicator is now painting correctly. However, I am still having difficulty trapping the mouse click correctly for the hit test. The AutoSortingColumn event seems to consume the mouse click because the CellClick event never fires regardless of the e.Cancel setting in the event. Also, setting the renderer's RightToLeft property seems to have no discernable effect. I thought maybe I could fake the left side by setting RightToLeft to True. Thanks in advance for any ideas and/or suggestions!
  • Replied 8 September 2017, 1:25 pm EST

    Hello,


    This is an oversight on the developers part about the Renderer class. The IsReservedLocation and GetReservedCursor methods are implemented on the IEditor interface. So even though you can use the mouse posistion on the mouse down event to determine where relative to the column header rectangle you are so that you can programatically call the Sort method if you want, there is no way to notify the user that the mouse is over a certain location of the column header.


    I have added this as an Enhancement request for the development team to implement a way to provide this functionality.

  • Replied 8 September 2017, 1:25 pm EST

    Hello ScottS,


    Sorry, but I lost you on this one.


    1. Why doesn't the SortIndicator paint on the left side since I overrode the PaintSortIndicator method and created a new rectangle before calling MyBase.PaintSortIndicator? The debug code shows that the new rectangle is on the left instead of on the right.


    2. How do I cancel the hit test so the column doesn't sort if the user clicks on the right?

  • Replied 8 September 2017, 1:25 pm EST

    Hello,


    1) You are not seeing the sort indicator because you are painting it in the wrong rectangle. I created a private variable to hold the rectangle of the header passed into the PaintHeader override and used it's starting location to paint the sort indicator in the PaintSortIndicator override.


    Private headerRect As Rectangle


    ...


    Public Overrides Sub PaintHeader(ByVal g As System.Drawing.Graphics, ByVal r As System.Drawing.Rectangle, ByVal rectTextIn As System.Drawing.Rectangle, ByVal backColor As System.Drawing.Color, ByVal foreColor As System.Drawing.Color, ByVal font As System.Drawing.Font, ByVal halign As FarPoint.Win.HorizontalAlignment, ByVal valign As FarPoint.Win.VerticalAlignment, ByVal pressed As Boolean, ByVal focus As Boolean, ByVal text As String, ByVal textDown As String, ByVal nAlign As FarPoint.Win.ButtonTextAlign, ByVal textOrientation As FarPoint.Win.TextOrientation, ByVal wordWrap As Boolean, ByVal shadowSize As Integer, ByVal darkColor As System.Drawing.Color, ByVal lightColor As System.Drawing.Color, ByVal pictUp As System.Drawing.Image, ByVal pictDown As System.Drawing.Image, ByVal bLocked As Boolean, ByVal prefix As System.Drawing.Text.HotkeyPrefix, ByVal style As FarPoint.Win.VisualStyles, ByVal mouseOver As Boolean, ByVal rightToLeft As Boolean, ByVal appearance As FarPoint.Win.Spread.Appearance, ByVal textRotationAngle As Double)


    Try


    Dim location As Rectangle


    headerRect = r


    ...


    End Sub


    Public Overrides Sub PaintSortIndicator(ByVal g As System.Drawing.Graphics, ByVal r As System.Drawing.Rectangle, ByVal appearance As FarPoint.Win.Spread.Appearance, ByVal zoomFactor As Single)


    Try


    ...


    Case SortIndicatorPositions.Left


    Dim newLocation As Rectangle


    With r


    newLocation = New Rectangle(New Point(headerRect.X, .Y), New Size(.Width, .Height))


    ...


    End Sub


    2) In the AutoSortingColumn event, set the e.Cancel parameter to True to keep the Spread from automatically sorting. Then you can write code to programatically sort when you get a click in a certain area of the rectangle.

  • Replied 8 September 2017, 1:25 pm EST

    Hello Scott,


    We are getting closer. In your example just above, shouldn't the Y value for sortR = r.Y + 2 since the rectangle is a 16x16 bitmap and the height is 20? Also, once that change is made, then sortR is exactly the same as Private headerRect As Rectangle which you introduced earlier in the thread to help the SortIndicator paint correctly.


    When the user clicks on the Left side where the Sort Indicator is displayed, the entire column is selected. I tried to use the ClearSelection method but it doesn't seem to work. Thanks again for the responses!

  • Replied 8 September 2017, 1:25 pm EST

    Hello,


    The CellClick should only not fire if they click in the area the sort indicator would be by default, but that should not matter since you do not want to sort on a click in that location. Here is code in the CellClick event to see if they are clicking the rectangle the sort indicator is now painting based on the earlier code.


    Private Sub FpSpread1_CellClick(ByVal sender As Object, ByVal e As FarPoint.Win.Spread.CellClickEventArgs) Handles FpSpread1.CellClick


    If e.ColumnHeader Then


    Dim r As Rectangle = FpSpread1.GetRootWorkbook.GetColumnHeaderCellRectangle(0, e.Row, e.Column)


    Dim sortR As Rectangle = New Rectangle(r.X, r.Y, 16, 16)


    Dim p As Point = New Point(e.X, e.Y)


    If sortR.Contains(p) Then


    FpSpread1.Sheets(0).SortRows(e.Column, True, True)


    End If


    End If


    End Sub

  • Replied 8 September 2017, 1:25 pm EST

    Thanks ScottS, I should have thought of that myself. 


    I want to encapsulate as much of this code as possible in my inherited class so I am using Reflection to get a MethodInfo object for the OnAutoColumnSorting method. I can then use Invoke to fire the AutoColumnSorting event on the parent form.


    1. Where do I get the information needed to set up the AutoSortingColumnEventArgs class


    2. Even though I am cancelling the AutoSortingColumn event when someone clicks on the right side, it still flips the SortIndicator which is displayed on the left side


    Thanks in advance for any ideas and/or suggestions!

  • Replied 8 September 2017, 1:25 pm EST

    Hello,


    You can create a new AutoSortingColumnEventArgs object to pass in, but you would need to know information to create each parameter.


    Dim asc As New FarPoint.Win.Spread.AutoSortingColumnEventArgs(FpSpread1.Sheets(0), 1, True, True)

  • Replied 8 September 2017, 1:25 pm EST

    Hello,


    I did not communicate well in my prior post. When a SortIndicator is on the left, no AutoColumnSorting event is called when the user clicks it. I am detecting this in the CellClick event for the ColumnHeader. So I need to manually raise the event via OnAutoSortingColumn. That is why I need to know how to set up the event args. Thanks in advance for any ideas and/or suggestions!

  • Replied 8 September 2017, 1:25 pm EST

    Hello,


    1) You should get the AutoSortingColumnEventArgs as a parameter in the onAutoSortingColumn method. Then, you can fire the event with the information from this parameter.


    2) I am not seeing this behavior after I canceled the AutoSortingColumn event.

  • Replied 8 September 2017, 1:25 pm EST

    Hello,


    Yes. The sortR rectangle should be the same as headerRect in the CellType. Set the e.Cancel parameter to True in the CellClick event to keep the entire column from being selected.

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels