.NET Vertical Scrollbar not Respecting Maximum Property
I have a form and have dropped a vertical scrollbar on it.
Whatever I set the "Maximum" property to,开发者_运维问答 the scrollbar will only scroll up to that value minus 9.
Why is that?
I'm using C# in Visual Studio 2008. (WinForms)
After some research, I've found that a scroll bar can only go up to it's maximum minus the size of the scrollbar's slider.
And the size of the slider appears to be equal to (LargeChange - 1).
Doesn't seem very intuitive to me but there you go.
The default value of LargeChange property is 10. This value is used when scrollbar is incremented by clicking the right arrow. If you want to show all values (assuming 1,2,3,4,...) with mouse clicks, set LargeChange = 1
Thanks to Kevin for explaining this! I made a custom vertical scroll bar in VB .NET that addresses this problem and also:
- Maps the Minimum, Maximum, and Value to real-world coordinates RealMaximum, RealMinimum, and RealValue
- Adds a SetMaximum property that should be set to the value you would normally set the Maximum property to. Maximum will be rescaled to take the slider width into account.
- Inverts the scroll behavior so that scrolling upward returns a higher value and scrolling downward returns a lower value.
Here's the code:
Public Class VScrollBarPlus
Inherits System.Windows.Forms.VScrollBar
' Maps the VScrollbar integer min and max to a double-precision set of minima and maxima '
' RealValue is scaled to RealMaximum and RealMinimum'
' The vertical scrollbar should scroll UP to maximum and DOWN to minimum, not the other way around'
' A VB slider width is LargeChange -1'
' The regular VB scroll bar can only go up to its maximum minus the width of the scrollbar's slider.'
' The SetMaximum property should be set to the maximum value you WANT'
' The Maximum property will be rescaled to take into account the slider width'
' Slope and intercept to calculate actual value'
Private slope As Double = 1
Private intercept As Double = 0
' Internal variables for real max, real min, and real value'
Private rValue As Double
Private rMin As Double
Private rMax As Double
Private sMax As Double
Property SetMaximum As Double ' The value you _want_ to set as maximum'
' The actual Maximum will be set to SetMaximum + LargeChange - 1 to allow scrolling to maximum value'
Get
SetMaximum = sMax
End Get
Set(svalue As Double)
sMax = svalue
Maximum = SetMaximum + LargeChange - 1
End Set
End Property
Property RealMaximum As Double ' Real-world coordinates'
Get
RealMaximum = rMax
End Get
Set(svalue As Double)
rMax = svalue
End Set
End Property
Property RealMinimum As Double ' Real-world coordinates'
Get
RealMinimum = rMin
End Get
Set(svalue As Double)
rMin = svalue
End Set
End Property
Property RealValue As Double ' Real-world coordinates'
Get
slope = (rMax - rMin) / (sMax - CDbl(Minimum))
intercept = rMax - slope * sMax
' Use the negative Value to invert slider motion'
RealValue = slope * CDbl(-Value) + intercept
End Get
Set(svalue As Double)
rValue = svalue
If slope <> 0 Then
Value = Math.Min(SetMaximum, -(rValue - intercept) / slope)
Else
Value = SetMaximum
End If
End Set
End Property
End Class
I made a test form with a VScrollBarPlus control and four text boxes: two to display/set the real-world coordinates and two to display the scrollbar value and the value mapped to real world coordinates. These were names txtMin, txtMax, txtScrollValue and txtValue respectively. In the designer, I set the Minimum and Maximum properties to -1000 and 1000, SetMaximum to 1000, RealMinimum to -1, RealMaximum to 1, RealValue to 1, LargeChange to 10 and SmallChange to 1. The value for SetMaximum must be set in the designer or code before using the scrollbar.
Here is the code for the test form.
Public Class Test_Form
Private Sub txtMin_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtMin.KeyPress
If e.KeyChar = Chr(Keys.Enter) Then
VScrollBarPlus1.RealMinimum = CDbl(txtMin.Text)
End If
End Sub
Private Sub txtMax_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtMax.KeyPress
If e.KeyChar = Chr(Keys.Enter) Then
VScrollBarPlus1.RealMaximum = CDbl(txtMax.Text)
End If
End Sub
Private Sub VScrollBarPlus1_Scroll(sender As Object, e As ScrollEventArgs) Handles VScrollBarPlus1.Scroll
If e.Type = ScrollEventType.EndScroll Then
txtValue.Text = VScrollBarPlus1.RealValue.ToString
txtScrollValue.Text = VScrollBarPlus1.Value.ToString
End If
End Sub
Private Sub Test_Form_Load(sender As Object, e As EventArgs) Handles Me.Load
VScrollBarPlus1.Maximum = 1000
VScrollBarPlus1.Minimum = -1000
txtMax.Text = 9.5
txtMin.Text = -7
VScrollBarPlus1.RealMaximum = 9.5
VScrollBarPlus1.RealMinimum = -7
VScrollBarPlus1.SetMaximum = VScrollBarPlus1.Maximum ' will resize Maximum '
VScrollBarPlus1.RealMaximum = CDbl(txtMax.Text)
VScrollBarPlus1.RealMinimum = CDbl(txtMin.Text)
End Sub
Private Sub txtValue_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtValue.KeyPress
If e.KeyChar = Chr(Keys.Enter) Then
VScrollBarPlus1.RealValue = CDbl(txtValue.Text)
txtScrollValue.Text = VScrollBarPlus1.Value.ToString
End If
End Sub
End Class
I like the scroll bar as a quick input device but the bug pointed out here was a problem. Syed is right that you can just reduce the LargeChange
property to 1 and the scrollbar will move to its maximum value.
However, if you want to keep the LargeChange
property at some larger value, say 10 for quick scrolling, use the ValueChanged
event. When the value is below 90 (or below Maximum - LargeChange
), leave the LargeChange
property at 10. When the value goes to 90 or above, change the LargeChange
property to 1.
This allows the scrollbar to behave normally (or very nearly so) while still going to its maximum.
精彩评论