首页 文章

自动将列装入Listview以获得垂直滚动条

提问于
浏览
2

我继承了Listview来执行一些小的更改,但我想改进usercontrol类或Form类中的任何地方的设计,因为我对Listview的默认大小调整机制不满意 .

在Form Class中,我调整了最后一列(“Download”),如下所示:

ColumnDownload.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize)

问题是当(默认)滚动条出现在列表视图中时,最后一列的大小不会自动固定/减小,因此水平和未嵌入的滚动条也会自动出现 .

然后有人可以帮我解释一下如何在滚动条出现时自动修复最后一列的大小?我很失落 .

NOTE: 我需要说'm not looking for alternative LV',如 ObjectListView .

NOTE 2 :我不知道'm not performing any auto-resize improvement at the moment there, I don'因为我知道从哪里开始 .

这是我的Listview正常:

enter image description here

这与填充项目的列表视图相同:

enter image description here

2 回答

  • 3

    when the (default) scrollbar appears inside the listview the size of the last column is not automatically fixed/decreased ... "default scrollbar"被视为Veritical Scroll .

    AutoResize 不是 AutoFit . 它用于根据页眉文本范围或内容长度调整列的大小,而不是管理滚动条并且工作得很好 . 如果它确实自动调整了最后一列的大小,当最后一列是一个小型的'OK?'类型列时,我们会生气,当它被AutoFitted消除时它变得不可读 .

    PInvokes在 NativeMethods 班;这些吃滚动条,并得到它们是否显示 .

    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
    

    Steal xx pixels from the last column; Put the pixels back if the VScroll goes away.

    基本上发生的事情是 ClientSizeChanged 两次触发:1)当VScroll到达时,然后在HScroll由于VScroll而到达时再次出现一些微观 . 所以你必须处理两次事件 . 这会在第一遍中调整所需列的大小,并在第二行中调用HScroll . 即使在步骤1之后不再需要HScroll,如果您不手动删除它,它会短暂显示 .

    如果由于您的布局方式或用户调整列的大小而需要HScroll,则无论如何都会调整最后一列的大小,但不要吃HScroll . 缺少检测何时不需要第一步的额外逻辑(您通常无法看到它执行此操作) .

    注意事项:我不知道这将如何或是否适用于第三方主题 . 我不认为主题可以修改这些内部滚动条 .

    另外, this is intended for use in a subclassed LV ,我知道你已经做过了 . 对于其他人,通过对引用进行一些修改,即使它在表单中留下了许多丑陋的代码,这也应该使用相关事件(例如 ClientSizeChanged )对表单进行更改 .

    这也不包含在 IF AutoFit 属性测试中 .

    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
    

    Sub New是 not orgClient 的好地方 - 尚未创建控件 . OnHandleCreated 会这样做,但是没有 ISupportInitialize ,我会在控件上调用一个新的Sub来代替它从Form_Load设置它 . 如果您想在手动调整列后再重新生成后再进行操作,这实际上可以很方便 . 例如:

    ' 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
    
  • 0

    或多或少我已经完成了所以我会发布这个解决方案,代码仍然有问题'因为它在我试图“播放”显示和隐藏滚动条它可以挂起的某些情况下没有按预期工作listview,并确保代码有不必要的检查,可以改进,但现在我没有更多的时间来尝试修复相关的问题,如果有人可以帮助修复此代码,以改善它,那么谢谢你:

    Dim SizeAlreadyDecreased As Boolean = False
    
    Private Sub ElektroListView_Downloads_ClientSizeChanged(sender As Object, e As EventArgs) _
    Handles ElektroListView_Downloads.ClientSizeChanged
    
        ' Retrieve all the column widths
        Dim AllColumnsWidth As Integer =
            (From col As ColumnHeader In CType(sender.Columns, ListView.ColumnHeaderCollection)
             Select col.Width).Sum
    
        ' Fix the last column width to fill the not-used blank space when resizing the Form.
        Me.ColumnDownload.Width =
            Me.ColumnDownload.Width + (sender.ClientSize.Width - AllColumnsWidth) - 2
    
        ' Fix the last column width to increase or decrease the size if a VertivalScrollbar appears.
        If GetScrollbars(sender) AndAlso Not SizeAlreadyDecreased Then
            SizeAlreadyDecreased = True
            ColumnDownload.Width -= SystemInformation.VerticalScrollBarWidth
    
        ElseIf GetScrollbars(sender) AndAlso SizeAlreadyDecreased Then
            SizeAlreadyDecreased = True
    
        ElseIf Not GetScrollbars(sender) AndAlso SizeAlreadyDecreased Then
            SizeAlreadyDecreased = False
            ColumnDownload.Width += SystemInformation.VerticalScrollBarWidth
    
        ElseIf Not GetScrollbars(sender) AndAlso Not SizeAlreadyDecreased Then
            SizeAlreadyDecreased = False
    
        End If
    
    End Sub
    
    Private Const WS_VSCROLL As Integer = &H200000I
    Private Const WS_HSCROLL As Integer = &H100000I
    Private Const GWL_STYLE As Integer = -16I
    
    <DllImport("user32.dll", CharSet:=CharSet.Auto)>
    Private Shared Function GetWindowLong(
            ByVal hWnd As HandleRef,
            ByVal nIndex As Integer
    ) As Integer
    End Function
    
    Public Function GetScrollbars(ByVal ctrl As Control) As ScrollBars
    
        Dim style As Integer = GetWindowLong(New HandleRef(ctrl, ctrl.Handle), GWL_STYLE)
    
        Dim HScroll As Boolean = ((style And WS_HSCROLL) = WS_HSCROLL)
        Dim VScroll As Boolean = ((style And WS_VSCROLL) = WS_VSCROLL)
    
        If (HScroll AndAlso VScroll) Then
            Return ScrollBars.Both
    
        ElseIf HScroll Then
            Return ScrollBars.Horizontal
    
        ElseIf VScroll Then
            Return ScrollBars.Vertical
    
        Else
            Return ScrollBars.None
    
        End If
    
    End Function
    

相关问题