The ScrollBar class has these properties to specify the thumb location and the thumb size:
- Value - represents the thumb position
- ViewportSize - represents the thumb location
ViewportSize varies between 0 and double.MaxValue. What!? What use is this to anyone?
What you nearly always have when you are implementing your own scrolling is the length of the thumb and the absolute position of the thumb. Here are some extension methods that convert these to and from the WPF properties.
public static class ScrollBarExtensions
{
public static double GetThumbCenter(this ScrollBar s)
{
double thumbLength = GetThumbLength(s);
double trackLength = s.Maximum - s.Minimum;
return thumbLength / 2 + s.Minimum + (s.Value - s.Minimum) *
(trackLength - thumbLength) / trackLength;
}
public static void SetThumbCenter(this ScrollBar s, double thumbCenter)
{
double thumbLength = GetThumbLength(s);
double trackLength = s.Maximum - s.Minimum;
if (thumbCenter >= s.Maximum - thumbLength / 2)
{
s.Value = s.Maximum;
}
else if (thumbCenter <= s.Minimum + thumbLength / 2)
{
s.Value = s.Minimum;
}
else if (thumbLength >= trackLength )
{
s.Value = s.Minimum;
}
else
{
s.Value = s.Minimum + trackLength *
((thumbCenter - s.Minimum - thumbLength / 2)
/ (trackLength - thumbLength));
}
}
public static double GetThumbLength(this ScrollBar s)
{
double trackLength = s.Maximum - s.Minimum;
return trackLength * s.ViewportSize /
(trackLength + s.ViewportSize);
}
public static void SetThumbLength(this ScrollBar s, double thumbLength)
{
double trackLength = s.Maximum - s.Minimum;
if (thumbLength < 0)
{
s.ViewportSize = 0;
}
else if (thumbLength < trackLength )
{
s.ViewportSize = trackLength * thumbLength / (trackLength - thumbLength);
}
else
{
s.ViewportSize = double.MaxValue;
}
}
}
ScrollBarExtensions.cs
2 comments:
Much appreciated - the guys that wrote WPF are pretty smart so am sure there's good reason for the scrollbar/thumb relationship being so arcane (or maybe it was just a Friday :-)) but your code's saved me walking the exact same path!!
I agree - they've certainly gone with this implementation for some good reason. It would just be nice to know what that reason is.
Post a Comment