Setting the Scrollbar Thumb size

后端 未结 5 1127
醉梦人生
醉梦人生 2021-02-05 17:01

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.ViewportSi

相关标签:
5条回答
  • 2021-02-05 17:15

    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 讨论(0)
  • 2021-02-05 17:17

    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!

    0 讨论(0)
  • 2021-02-05 17:23

    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.

    0 讨论(0)
  • 2021-02-05 17:24

    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>
    
    0 讨论(0)
  • 2021-02-05 17:30

    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
    }
    

    }

    0 讨论(0)
提交回复
热议问题