开发者

Setting the Scrollbar Thumb size

I am attempting to work out the algorithm associated with sizing of the WPF Scrollbar thumb element.

The thumb element can be sized using the Scrollbar.ViewportSize property, but it in turn is related to the Scrollbar.Minimum and Scrollbar.Maximum values.

What I have discovered so far is:

For a Minimum and Maximum of 0 and 10, a ViewportSize of:

0 - Thumb minimum size

5 - Thumb approximately 25% of the available track

10 - Thumb approximately 50% of the available track

100 - Thumb approximately 75% of the available track

1000 - Thumb approximately 90% of the available开发者_StackOverflow track

10000 - Thumb fills the available track.

[note: these figures are only from my rough trial and error!]

Ideally I'd like to be able to have an algorithm where given the minimum and maximum values for the Scrollbar I can set the thumb size to be exactly x% of the available track.

Can anyone help with this?

Thanks.


From: http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.track(VS.90).aspx

thumbSize = (viewportSize/(maximum–minimum+viewportSize))×trackLength

or re-arranging for viewportSize:

viewportSize = thumbSize×(maximum-minimum)/(trackLength-thumbSize)

You've prob found this already but thought I'd post in case others end up here.


On my side, I preserved a minimum thumb length because touch inputs require a thumb of a minimum size to be touch optimized.

You can define a ScrollViewer ControlTemplate that will use the TouchScrollBar as its horisontal and vertical ScrollBar.

See UpdateViewPort method for the math.

Sorry, I don't see the use case for explicitly setting the scrollbar thumb to cover a percentage of the track length

public class TouchScrollBar : System.Windows.Controls.Primitives.ScrollBar
{
    #region Fields

    #region Dependency properties

    public static readonly DependencyProperty MinThumbLengthProperty =
        DependencyProperty.Register
        ("MinThumbLength", typeof(double), typeof(TouchScrollBar), new UIPropertyMetadata((double)0, OnMinThumbLengthPropertyChanged));

    #endregion

    private double? m_originalViewportSize;

    #endregion

    #region Properties

    public double MinThumbLength
    {
        get { return (double)GetValue(MinThumbLengthProperty); }
        set { SetValue(MinThumbLengthProperty, value); }
    }

    #endregion

    #region Constructors

    public TouchScrollBar()
    {
        SizeChanged += OnSizeChanged;
    }

    private bool m_trackSubscribed;
    void OnSizeChanged(object sender, SizeChangedEventArgs e)
    {
        SubscribeTrack();
    }

    private void SubscribeTrack()
    {
        if (!m_trackSubscribed && Track != null)
        {
            Track.SizeChanged += OnTrackSizeChanged;
            m_trackSubscribed = true;
        }

    }

    #endregion

    #region Protected and private methods

    #region Event handlers

    #region Dependency properties event handlers

    private void OnMinThumbLengthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        TouchScrollBar instance = d as TouchScrollBar;
        if(instance != null)
        {
            instance.OnMinThumbLengthChanged(e);

        }
    }

    #endregion

    protected void OnTrackSizeChanged(object sender, SizeChangedEventArgs e)
    {
        SubscribeTrack();
        UpdateViewPort();
    }

    protected override void OnMaximumChanged(double oldMaximum, double newMaximum)
    {
        base.OnMaximumChanged(oldMaximum, newMaximum);

        SubscribeTrack();
        UpdateViewPort();
    }

    protected override void OnMinimumChanged(double oldMinimum, double newMinimum)
    {
        base.OnMinimumChanged(oldMinimum, newMinimum);

        SubscribeTrack();
        UpdateViewPort();
    }

    protected void OnMinThumbLengthChanged(DependencyPropertyChangedEventArgs e)
    {
        SubscribeTrack();
        UpdateViewPort();
    }

    #endregion

    private void UpdateViewPort()
    {
        if(Track != null)
        {
            if(m_originalViewportSize == null)
            {
                m_originalViewportSize = ViewportSize;
            }

            double trackLength = Orientation == Orientation.Vertical ? Track.ActualHeight : Track.ActualWidth;
            double thumbHeight = m_originalViewportSize.Value / (Maximum - Minimum + m_originalViewportSize.Value) * trackLength;
            if (thumbHeight < MinThumbLength && !double.IsNaN(thumbHeight))
            {
                ViewportSize = (MinThumbLength * (Maximum - Minimum)) / (trackLength + MinThumbLength);
            }
        }
    }


    #endregion
}

}


Here's a method that will override the thumb minimum width for all ScrollBars. There's 2 important reasons for using this setup.

1) This will not resize the ScrollBar RepeatButtons. (Why the style overrides Track)

2) This will only resize the thumbs for Track controls that are used in ScrollBars. (Why the Track style is contained in a ScrollBar style.

<!-- Override for all styles -->
<Style TargetType="{x:Type ScrollBar}" BasedOn="{StaticResource {x:Type ScrollBar}}">
    <Style.Resources>
        <Style TargetType="{x:Type Track}">
            <Style.Resources>
                <System:Double x:Key="{x:Static SystemParameters.VerticalScrollBarButtonHeightKey}">48</System:Double>
                <System:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarButtonWidthKey}">48</System:Double>
            </Style.Resources>
        </Style>
    </Style.Resources>
</Style>

<!-- Override for a certain control -->
<!-- The ScrollBar Style part in the middle can be safely ommited
if you can guarantee the control only uses Tracks for ScrollBars -->
<SomeControl>
    <SomeControl.Resources>
        <Style TargetType="{x:Type ScrollBar}" BasedOn="{StaticResource {x:Type ScrollBar}}">
            <Style.Resources>
                <Style TargetType="{x:Type Track}">
                    <Style.Resources>
                        <System:Double x:Key="{x:Static SystemParameters.VerticalScrollBarButtonHeightKey}">48</System:Double>
                        <System:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarButtonWidthKey}">48</System:Double>
                    </Style.Resources>
                </Style>
            </Style.Resources>
        </Style>
    </SomeControl.Resources>
</SomeControl>


If you're looking for how to set a minimum height for the scrollbar thumb:

From Ian (da real MVP) here:

scrollBar1.Track.ViewportSize = double.NaN;  
scrollBar1.Track.Thumb.Height = Math.Max(minThumbHeight, DataScrollBar.Track.Thumb.ActualHeight);

Or you know, add 100+ lines of xaml code cause omgDATABINDING!!1!


Scrollbar thumb size for UWP:

    static void SetViewportSize(ScrollBar bar, double size)
    {
        var max = (bar.Maximum - bar.Minimum);
        bar.ViewportSize = size / (max - size) * max;
        bar.IsEnabled = (bar.ViewportSize >= 0 &&
            bar.ViewportSize != double.PositiveInfinity);
        InvalidateScrollBar(bar);
    }

    static void InvalidateScrollBar(ScrollBar bar)
    {
        var v = bar.Value;
        bar.Value = (bar.Value == bar.Maximum) ? bar.Minimum : bar.Maximum;
        bar.Value = v;
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜