WPF中文网

ScrollBar滚动条

ScrollBar表示一个滚动条,该滚动条具有一个滑动 Thumb,其位置对应于一个值。它继承于RangeBase抽象基类,RangeBase基类继承于Control基类。带滚动特质的还有两个控件,也继承于RangeBase抽象基类,它们分别是ProgressBar(进度条)和Slider(滑动条)。待我们探讨完ScrollBar,再来探讨ProgressBar和Slider。

一、RangeBase抽象基类定义

public abstract class RangeBase : Control
{
    public static readonly RoutedEvent ValueChangedEvent;
    public static readonly DependencyProperty MinimumProperty;
    public static readonly DependencyProperty MaximumProperty;
    public static readonly DependencyProperty ValueProperty;
    public static readonly DependencyProperty LargeChangeProperty;
    public static readonly DependencyProperty SmallChangeProperty;

    protected RangeBase();

    public double LargeChange { get; set; }
    public double SmallChange { get; set; }
    public double Value { get; set; }
    public double Maximum { get; set; }
    public double Minimum { get; set; }

    public event RoutedPropertyChangedEventHandler<double> ValueChanged;

    public override string ToString();
    protected virtual void OnMaximumChanged(double oldMaximum, double newMaximum);
    protected virtual void OnMinimumChanged(double oldMinimum, double newMinimum);
    protected virtual void OnValueChanged(double oldValue, double newValue);

}

RangeBase 只有5个属性

属性名称说明
LargeChange 表示给Value属性加减的最大值。默认为1
SmallChange 表示给Value属性加减的最小值。默认为0.1
Value 获取或设置范围控件的当前数量。默认为0
Maximum 获取或设置Value属性的最大值
Minimum 获取或设置Value属性的最小值

RangeBase事件成员

ValueChanged:当前Value属性发生改变时触发的事件。

总结,ScrollBar、ProgressBar和Slider都将继承上面的属性、方面与事件成员。

二、ScrollBar类定义

public class ScrollBar : RangeBase
{
    public static readonly RoutedEvent ScrollEvent;
    public static readonly RoutedCommand ScrollHereCommand;
    public static readonly RoutedCommand DeferScrollToVerticalOffsetCommand;
    public static readonly RoutedCommand DeferScrollToHorizontalOffsetCommand;
    public static readonly RoutedCommand ScrollToVerticalOffsetCommand;
    public static readonly RoutedCommand ScrollToHorizontalOffsetCommand;
    public static readonly RoutedCommand ScrollToTopCommand;
    public static readonly RoutedCommand ScrollToLeftEndCommand;
    public static readonly RoutedCommand ScrollToRightEndCommand;
    public static readonly RoutedCommand ScrollToHomeCommand;
    public static readonly RoutedCommand ScrollToEndCommand;
    public static readonly RoutedCommand ScrollToBottomCommand;
    public static readonly RoutedCommand PageLeftCommand;
    public static readonly RoutedCommand PageDownCommand;
    public static readonly RoutedCommand PageUpCommand;
    public static readonly RoutedCommand LineRightCommand;
    public static readonly RoutedCommand PageRightCommand;
    public static readonly RoutedCommand LineLeftCommand;
    public static readonly RoutedCommand LineDownCommand;
    public static readonly RoutedCommand LineUpCommand;
    public static readonly DependencyProperty ViewportSizeProperty;
    public static readonly DependencyProperty OrientationProperty;

    public ScrollBar();

    public Orientation Orientation { get; set; }
    public double ViewportSize { get; set; }
    public Track Track { get; }
    protected override bool IsEnabledCore { get; }

    public event ScrollEventHandler Scroll;

    public override void OnApplyTemplate();
    protected override void OnContextMenuClosing(ContextMenuEventArgs e);
    protected override void OnContextMenuOpening(ContextMenuEventArgs e);
    protected override AutomationPeer OnCreateAutomationPeer();
    protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e);
    protected override void OnPreviewMouseRightButtonUp(MouseButtonEventArgs e);

}

ScrollBar自身有两个属性是我们必须要掌握的,那就是Orientation 和ViewportSize 。

Orientation :表示当前滚动条是水平的还是垂直的。

ViewportSize:获取或设置当前可见的可滚动内容的数量。默认值为0。

另外,它还有一个滚动事件Scroll可以使用。我们还是以实际的例子来说明它的用法吧。

前端代码

<Window x:Class="HelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:HelloWorld"
        mc:Ignorable="d" FontSize="16"
        Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
    <Grid x:Name="viewport" >
        <Grid.RowDefinitions>
            <RowDefinition Height="115"/>
            <RowDefinition Height="auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Canvas>
            <StackPanel x:Name="element" Orientation="Horizontal" Canvas.Left="{Binding CanvasLeft}">
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
                <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="5" Padding="3" Margin="3">
                    <Image Source="pack://application:,,,/Images/logo.png" Width="100" Height="100"/>
                </Border>
            </StackPanel>
        </Canvas>        
        <ScrollBar Grid.Row="1" Orientation="Horizontal" 
                   Maximum="{Binding Maximum}"
                   Value="{Binding X}"
                   ViewportSize="{Binding ElementName=viewport,Path=ActualWidth}"/>
        <TextBlock Grid.Row="2" Text="ScrollBar" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24"/>
    </Grid>
</Window>

观察这个UI设计,我们故意在StackPanel控件中增加了多张图片,使其不能完全在Canvas中显示出来,然后在下面实例化了一根水平滚动条。注意滚动条的其中三个参数使用了绑定,不熟悉的小伙伴可参阅数据绑定那一章节。

Maximum:表示这根滚动条的最大值。

Value:表示滚动条的当前值。

ViewportSize:表示滚动条要作用于某个控件的宽度(这里实际上指Grid的宽度)。

最后,我们将StackPanel控件的Canvas.Left依赖属性绑定到一个CanvasLeft属性。只要CanvasLeft属性的值发生改变,那么StackPanel相对于Canvas水平位置就发生改变。

那么CanvasLeft属性是怎样发生改变的呢?这一切将在后台代码中实现。

后端代码

using System.ComponentModel;
using System.Windows;

namespace HelloWorld
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window,INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;//将当前窗体作为ViewModel赋值给当前窗体的DataContext
            Loaded += (s, e) =>
            {
                //计算滚动条的最大值
                Maximum = element.ActualWidth - viewport.ActualWidth;
            };
        }

        private double maximum = 0;
        /// <summary>
        /// 滚动条的最大值
        /// </summary>
        public double Maximum
        {
            get { return maximum; }
            set { maximum = value; NotifyPropertyChanged("Maximum"); }
        }

        private double x = 0;
        /// <summary>
        /// 滚动条的当前值
        /// </summary>
        public double X
        {
            get { return x; }
            set { x = value; CanvasLeft = -x; NotifyPropertyChanged("X"); }
        }

        private double canvasLeft = 0;
        /// <summary>
        /// 相对于Canvas控件Left边距
        /// </summary>
        public double CanvasLeft
        {
            get { return canvasLeft; }
            set { canvasLeft = value; NotifyPropertyChanged("CanvasLeft"); }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 属性通知方法
        /// </summary>
        /// <param name="propertyName"></param>
        protected virtual void NotifyPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

如上所示,我们获取到滚动条的值X,然后取反后赋值给CanvasLeft属性,而CanvasLeft属性拥有“属性通知”功能,故而前端StackPanel的相对位置会随着用户拖动滚动条而变化。

关于属性通知及INotifyPropertyChanged接口,我们将在数据绑定一章讲解。

掌握了ScrollBar的用法后,Slider控件也基本就掌握了,下一节,我们来探讨Slider。对了,如果把下面这段代码换成Slider控件,也是可以用的哦。

更换前

<ScrollBar Grid.Row="1" Orientation="Horizontal" 
                   Maximum="{Binding Maximum}"
                   Value="{Binding X}"
                   ViewportSize="{Binding ElementName=viewport,Path=ActualWidth}"/>

更换后

<Slider Grid.Row="1" Maximum="{Binding Maximum}" Value="{Binding X}"/>

当前课程源码下载:(注明:本站所有源代码请按标题搜索)

文件名:030-《ScrollBar滚动条》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff

——重庆教主 2023年8月29日

copyright @重庆教主 WPF中文网 联系站长:(QQ)23611316 (微信)movieclip (QQ群).NET小白课堂:864486030 | 本文由WPF中文网原创发布,谢绝转载 渝ICP备2023009518号-1