Winforms(水平)滚动条无法解释的行为

时间:2014-10-17 23:44:31

标签: winforms

当我使用窗体右下角的调整大小手柄调整窗体大小时,它会触发用户控件的sizechanged事件。在用户控件内部,我有代码来设置水平滚动条的最大值和值。

如果我向右调整大小,则代码按预期工作。当我向左调整大小时,滚动的拇指变得非常大,滚动不能按预期工作。好像最大值被设置为一个较低的数字,但是我的Debug.WriteLine表明情况并非如此。实际上,当我慢慢地将表格调整为更窄时,它会在做正确和做错之间快速切换。

我很少处理滚动条,当我这样做时,它们总是很痛苦。是否有一位ScrollBar大师知道为什么会这样?我搜索了它并搜索了它,但我真的不知道该搜索什么。

这是我的代码。相关部分是从sizechanged事件处理程序调用的,它几乎是代码的底部。

Imports System.Reflection

Public Class Grid


  Public Sub New()

    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.
    SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or ControlStyles.DoubleBuffer, True) 'Or ControlStyles.ResizeRedraw 
  End Sub


  Private _FirstVisibleRow As Row
  Private Property FirstVisibleRow As Row
    Get
      If _FirstVisibleRow Is Nothing And Rows.Any Then
        _FirstVisibleRow = Rows.First
      End If
      Return _FirstVisibleRow
    End Get
    Set(value As Row)
      _FirstVisibleRow = value
      LastVisibleRow = GetLastVisibleRow()
    End Set
  End Property


  Private _HeaderRow As Row
  Public Property HeaderRow As Row
    Get
      If _HeaderRow Is Nothing Then
        _HeaderRow = New Row(Me, RowHeight)
        For Each Column As Column In Columns
          _HeaderRow.Cells.Add(New Cell(Column, _HeaderRow))
        Next
      End If
      Return _HeaderRow
    End Get
    Private Set(value As Row)
      _HeaderRow = value
    End Set
  End Property

  Private _LastVisibleRow As Row
  Private Property LastVisibleRow As Row
    Get
      If _LastVisibleRow Is Nothing Then
        _LastVisibleRow = GetLastVisibleRow()
      End If
      Return _LastVisibleRow
    End Get
    Set(value As Row)
      _LastVisibleRow = value
    End Set
  End Property


  Private _TotalColumnWidth As Integer
  Friend Property TotalColumnWidth As Integer
    Get
      If _TotalColumnWidth = Nothing Then
        _TotalColumnWidth = GetTotalColumnWidth()
      End If
      Return _TotalColumnWidth
    End Get
    Set(value As Integer)
      _TotalColumnWidth = value
      SetScrollBarVisibility()
    End Set
  End Property

  Private _TotalRowHeight As Integer
  Friend Property TotalRowHeight As Integer
    Get
      If _TotalRowHeight = Nothing Then
        _TotalRowHeight = GetTotalRowHeight()
      End If
      Return _TotalRowHeight
    End Get
    Set(value As Integer)
      _TotalRowHeight = value
      SetScrollBarVisibility()
    End Set
  End Property

  Private _VisibleGridSize As Size
  Private Property VisibleGridSize As Size
    Get
      If _VisibleGridSize = Nothing Then
        _VisibleGridSize = GetVisibleGridSize()
      End If
      Return _VisibleGridSize
    End Get
    Set(value As Size)
      _VisibleGridSize = value
      VisibleRowCount = GetVisibleRowCount()
      SetScrollBarVisibility()
    End Set
  End Property

  Private Sub SetScrollBarVisibility()
    VScrollBar1.Bounds = New Rectangle(Width - VScrollBar1.Width, 0, VScrollBar1.Width, Height - IIf(HScrollBar1.Visible, HScrollBar1.Height, 0))
    HScrollBar1.Bounds = New Rectangle(0, Height - HScrollBar1.Height, Width - IIf(VScrollBar1.Visible, VScrollBar1.Width, 0), HScrollBar1.Height)
    VScrollBar1.Maximum = Math.Max(0, TotalRowHeight - Height - IIf(HScrollBar1.Visible, HScrollBar1.Height, 0))
    HScrollBar1.Maximum = Math.Max(0, TotalColumnWidth - Width + IIf(VScrollBar1.Visible, VScrollBar1.Width, 0))
    HScrollBar1.Value = 0
    VScrollBar1.Visible = TotalRowHeight > VisibleGridSize.Height
    HScrollBar1.Visible = TotalColumnWidth > VisibleGridSize.Width
    Debug.WriteLine(String.Format("HScrollBar1.Minimum {0}, HScrollBar1.Maximum {1}, HScrollBar1.Value {2}", HScrollBar1.Minimum, HScrollBar1.Maximum, HScrollBar1.Value))
  End Sub

  Private _VisibleRowCount As Integer
  Private Property VisibleRowCount As Integer
    Get
      If _VisibleRowCount = 0 Then
        _VisibleRowCount = GetVisibleRowCount()
      End If
      Return _VisibleRowCount
    End Get
    Set(value As Integer)
      _VisibleRowCount = value
      LastVisibleRow = GetLastVisibleRow()
      PageHeight = GetPageHeight()
    End Set
  End Property

  Private Function GetLastVisibleRow() As Row
    If Not Rows.Any Then Return Nothing
    Return Rows(Math.Min(FirstVisibleRow.Index + VisibleRowCount - 1, Rows.Count - 1))
  End Function

  Private Function GetPageHeight() As Integer
    Return RowHeight * GetVisibleRowCount()
  End Function

  Private Function GetRowHeight() As Integer
    Return TextRenderer.MeasureText("X", Font).Height + 6
  End Function

  Private Function GetVisibleGridSize() As Size
    Return New Size(Width - IIf(VScrollBar1.Visible, VScrollBar1.Width, 0),
                    Height - HeaderRow.Height - IIf(HScrollBar1.Visible, HScrollBar1.Height, 0)) 'don't count header row or horiz scroll bar
  End Function

  Private Function GetVisibleRowCount() As Integer
    Return Math.Ceiling(VisibleGridSize.Height / RowHeight)
  End Function


  Public Shadows Sub Refresh()
    ClearSelection()
    _HeaderRow = Nothing
    _Rows = Nothing
    AutoSizeColumns()

    TotalRowHeight = GetTotalRowHeight()

    Invalidate()
  End Sub

  Friend Function GetTotalColumnWidth() As Integer
    Return Columns.Select(Function(x) x.Width).Aggregate(0, Function(x, y) x + y)
  End Function

  Friend Function GetTotalRowHeight() As Integer
    Return Rows.Select(Function(x) x.Height).Aggregate(0, Function(x, y) x + y)
  End Function

  Private Function VisibleRows() As List(Of Row)
    Return Rows.Where(Function(x) x.Index >= FirstVisibleRow.Index AndAlso x.Index <= LastVisibleRow.Index).ToList
  End Function

  Private Sub Grid_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    e.Graphics.Clear(BackColor)
    'e.ClipRectangle

    Dim Left As Integer = -HScrollBar1.Value
    For Each Column As Column In Columns
      Left = Column.Draw(e.Graphics, Left)
    Next

    Dim Top As Integer = HeaderRow.Draw(e.Graphics)
    For Each Row As Row In VisibleRows()
      Top = Row.Draw(e.Graphics, Top)
    Next
  End Sub

  Private Sub Grid_Scroll(sender As Object, e As System.Windows.Forms.ScrollEventArgs) Handles Me.Scroll
    If e.ScrollOrientation = ScrollOrientation.VerticalScroll Then
      Select Case e.Type
        Case ScrollEventType.First
          FirstVisibleRow = Rows.First
        Case ScrollEventType.Last
          FirstVisibleRow = Rows(Rows.Last.Index - VisibleRowCount + 1)
        Case ScrollEventType.SmallDecrement
          FirstVisibleRow = Rows(Math.Max(FirstVisibleRow.Index - 1, 0))
        Case ScrollEventType.SmallIncrement
          FirstVisibleRow = Rows(Math.Min(FirstVisibleRow.Index + 1, Rows.Last.Index - VisibleRowCount + 1))
        Case ScrollEventType.LargeDecrement
          FirstVisibleRow = Rows(Math.Max(FirstVisibleRow.Index - VisibleRowCount, 0))
        Case ScrollEventType.LargeIncrement
          FirstVisibleRow = Rows(Math.Min(LastVisibleRow.Index, Rows.Last.Index - VisibleRowCount + 1))
      End Select
    End If
    Invalidate()
  End Sub

  Private Sub Grid_SizeChanged(sender As Object, e As System.EventArgs) Handles Me.SizeChanged
    VisibleGridSize = GetVisibleGridSize()
  End Sub

  Private Sub HScrollBar1_Scroll(sender As Object, e As System.Windows.Forms.ScrollEventArgs) Handles HScrollBar1.Scroll
    Invalidate()
  End Sub

End Class

1 个答案:

答案 0 :(得分:0)

我的AutoScroll的{​​{1}}属性被父控件设置为UserControl。一旦我在设计器中将其设置回False,我的代码就会100%按预期运行。