且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

自动适应列到ListView控件的垂直滚动条

更新时间:2023-10-04 20:09:46

时,(默认)滚动条出现在列表视图的最后一列的大小不会自动固定在/下降 ...默认滚动条采取意味着Veritical滚动。

when the (default) scrollbar appears inside the listview the size of the last column is not automatically fixed/decreased ... "default scrollbar" taken to mean the Veritical Scroll.

自动调整不是自动调整。它是基于大小的标题文本范围或内容长度,而不是管理滚动条列,工作得很好。如果它没有自动调整最后一列,我们会生气时,最后一列是一个小的OK?键入这是无法读取,当它被AutoFitted走柱。

AutoResize is not AutoFit. It is for sizing columns based on the Header text extent or content length, not managing scrollbars and works very well. If it did automatically resize the last column, we would be angry when the last column is a small 'OK?' type column which was rendered unreadable when it was AutoFitted away.

NativeMethods 类PInvokes;这些吃的滚动条,并得到他们是否显示或不。

PInvokes in a NativeMethods class; these eat scrollbars and get whether they are showing or not.

Public Const WS_VSCROLL As Integer = &H200000
Public Const WS_HSCROLL As Integer = &H100000
Friend Enum SBOrientation As Integer
    SB_HORZ = &H0
    SB_VERT = &H1
    SB_CTL = &H2
    SB_BOTH = &H3
End Enum

<DllImport("user32.dll")> _
Private Shared Function ShowScrollBar(ByVal hWnd As IntPtr,
                     ByVal wBar As Integer,
                     <MarshalAs(UnmanagedType.Bool)> ByVal bShow As Boolean
                     ) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetWindowLong(ByVal hWnd As IntPtr, 
             ByVal nIndex As Integer) As Integer
End Function

Friend Shared Function IsHScrollVisible(ByVal ctl As Control) As Boolean
    Dim wndStyle As Integer = GetWindowLong(ctl.Handle, GWL_STYLE)
    Return ((wndStyle And WS_HSCROLL) <> 0)
End Function

Friend Shared Function IsVScrollVisible(ByVal ctl As Control) As Boolean
    Dim wndStyle As Integer = GetWindowLong(ctl.Handle, GWL_STYLE)
    Return ((wndStyle And WS_VSCROLL) <> 0)
End Function

Friend Shared Sub ShowHideScrollBar(ByVal ctl As Control, 
        ByVal sb As SBOrientation, ByVal bShow As Boolean)
     ShowScrollBar(ctl.Handle, sb, bShow)
End Sub

偷最后一列XX像素;把像素背,如果VSCROLL消失。

基本上什么情况是, ClientSizeChanged 触发两次:1)当VSCROLL到达随后又来了几个百万分之一后,当HSCROLL到达的VSCROLL的结果。所以,你必须处理该事件的两倍。这种调整大小在第一阶段所需的列,而吃HSCROLL中的第二个。即使HSCROLL的第1步后不再需要,它显示了简单,如果你不手动删除它。

Basically what happens is that ClientSizeChanged fires twice: 1) when the VScroll arrives then again a few micros later when the HScroll arrives as a result of the VScroll. So you have to process the event twice. This resizes the desired column in the first pass, and eats the HScroll in the second one. Even though the HScroll is no longer needed after Step 1, it shows up briefly if you dont remove it manually.

如果一个HS​​CROLL需要因为你把它的出路,或调整大小列的用户,它会调整最后一列反正,但不是吃HSCROLL。额外的逻辑,以检测当不需要第一步丢失(你不能看到它这样做,正常)。

If an HScroll is needed due to the way you laid it out or from the user resizing columns, it will resize the last column anyway, but not eat the HScroll. The extra logic to detect when the first step is not needed is missing (you cant see that it does it, normally).

注意事项:我不知道如何,或者如果这将与该第三方的主题。我不认为该主题可以修改内部滚动条这样的。

Caveats: I have no idea how or if this will work with this 3rd party theme. I dont think that the themes can modify internal scrollbars like these.

此外,这是为在子类LV 使用,我知道你已经做了。对于其他人,并涉及一些改造,这应该也是工作的一种形式,以推使用相关事件的变化(例如 ClientSizeChanged )的,即使它留下了很多丑陋的code形式。

Also, this is intended for use in a subclassed LV, which I know you have already done. For others, with some reworking of references, this should also work on a form to 'push' the changes using the related events (e.g. ClientSizeChanged) even if it leaves a lot of ugly code in the form.

这也心不是包裹在类似的如果自动调整性能测试。

This also isnt wrapped in something like an IF AutoFit property test.

Private orgClient As Rectangle      ' original client size for comparing
Private _VScrollWidth As Integer 

Private _resizedCol As Integer = -1
Private _VScroll As Boolean = False    ' persistent Scroll flags 
Private _HScroll As Boolean = False

' 3rd party???
_VScrollWidth = System.Windows.Forms.SystemInformation.VerticalScrollBarWidth

将这个地方,比如 ISupportInitialize.EndInit

orgClient = Me.ClientRectangle

子是新的不可以的好地方 orgClient - 被创建的控制处理不当。 OnHandleCreated 会做,但没有 ISupportInitialize接口,我将调用上控制了新的子由的Form_Load而是将它设置。这实际上可以方便地有,如果你想后,手动调整列然后再回到'重启'的东西。例如:

Sub New is not a good place for orgClient - the control hasnt been created yet. OnHandleCreated will do, but without ISupportInitialize, I would invoke a new Sub on the control to set it from Form_Load instead. This can actually be handy to have, if you want to 'restart' things after manually resizing columns then back again. For example:

' method on subclassed LV:   from form load: thisLV.ResetClientSize

Public Sub ResetClientSize          
   orgClient = Me.ClientRectangle   
End Sub


' a helper:
Private Function AllColumnsWidth() As Integer
    Dim w As Integer = 0
    For Each c As ColumnHeader In Columns
        w += c.Width
    Next
    Return w
End Function

' The Meat
Protected Overrides Sub OnClientSizeChanged(ByVal e As System.EventArgs)
    Dim VScrollVis As Boolean
    Dim HScrollVis As Boolean

    ' get who is Now Showing...local vars
    VScrollVis = NativeMethods.IsVScrollVisible(Me)
    HScrollVis = NativeMethods.IsHScrollVisible(Me)

     ' width change
    Dim delta As Integer = (orgClient.Width - ClientRectangle.Width)

    Dim TotalWidth As Integer = AllColumnsWidth()
    If (TotalWidth < ClientRectangle.Width - _VScrollWidth) And 
           (_resizedCol = -1) Then
        Exit Sub
    End If

    Me.SuspendLayout()

    ' If VScroll IS showing, but WASNT showing the last time thru here
    '  ... then we are here because VScroll just appeared.
    ' That being the case, trim the desired column
    If VScrollVis And _VScroll = False Then
        ' a smarter version finds the widest column and resizes THAT one
        _resizedCol = Columns.Count - 1

        ' we have to wait for the HScroll to show up
        ' to remove it
        Columns(_resizedCol).Width -= (delta + 1)

    End If

    ' HScroll just appeared
    If HScrollVis And (delta = _VScrollWidth) Then

        ' HScroll popped up, see if it is needed
        If AllColumnsWidth() <= orgClient.Width Then
            ' no, go away foul beast !
            NativeMethods.ShowHideScrollBar(Me,
                        NativeMethods.SBOrientation.SB_HORZ, False)

            _HScroll = False             ' hopefully

            ' allows us to set it back if the VScroll disappears
            orgClient = ClientRectangle
        Else
            ' ToDo: use this to detect when none of this is needed
            _HScroll = HScrollVis
        End If
    End If

    ' If VScroll ISNOT showing, but WAS showing the last time thru here
    '   ...then we are here because VScroll disappeared
    If VScrollVis = False And _VScroll = True Then
        ' put back the pixels

        If _resizedCol <> -1 Then
            Columns(_resizedCol).Width += (_VScrollWidth + 1)
            ' reset column tracker
            _resizedCol = -1
            ' reset to new compare size
            orgClient = ClientRectangle
        End If

    End If

    _VScroll = VScrollVis

    Me.ResumeLayout()

End Sub