通用Windows(UWP)范围滑块

问题描述:

我想在UWP中创建范围滑块.我没有找到任何例子.只有单个滑块,但我想要它
.

I want to create range slider in UWP. I didn't find any example. There are only single sliders but I want it like
.

有人知道我该怎么做吗?请帮助我.

Does anybody know how can i do it? Please help me.

要在UWP中创建范围滑块,我们可以创建自定义控件或使用

To create a range slider in UWP, we can create a custom control or use UserControl. Here I use UserControl for example:

首先,在项目中添加一个名为"MyRangeSlider"的UserControl.

Firstly, I add a UserControl named "MyRangeSlider" in my project.

在XAML中:

<UserControl x:Class="UWP.MyRangeSlider"
             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:local="using:UWP"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             d:DesignHeight="300"
             d:DesignWidth="400"
             mc:Ignorable="d">

    <Grid Height="32" Margin="8,0">
        <Grid.Resources>
            <Style TargetType="Thumb">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="Thumb">
                            <Ellipse Width="32"
                                     Height="32"
                                     Fill="White"
                                     RenderTransformOrigin="0.5 0.5"
                                     Stroke="Gray"
                                     StrokeThickness="1">
                                <Ellipse.RenderTransform>
                                    <TranslateTransform X="-16" />
                                </Ellipse.RenderTransform>
                            </Ellipse>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Grid.Resources>
        <Rectangle Height="16"
                   Margin="8,0"
                   Fill="#FFD5D5D5"
                   RadiusX="5"
                   RadiusY="5" />
        <Canvas x:Name="ContainerCanvas" Margin="8,0" SizeChanged="ContainerCanvas_SizeChanged">
            <Thumb x:Name="MinThumb" DragCompleted="MinThumb_DragCompleted" DragDelta="MinThumb_DragDelta" />
            <Thumb x:Name="MaxThumb" DragCompleted="MaxThumb_DragCompleted" DragDelta="MaxThumb_DragDelta" />
            <Rectangle x:Name="ActiveRectangle"
                       Canvas.Top="8"
                       Height="16"
                       Canvas.ZIndex="-1"
                       Fill="#FF69A0CC" />
        </Canvas>
    </Grid>
</UserControl>

及其背后的代码:

public sealed partial class MyRangeSlider : UserControl
{
    public double Minimum
    {
        get { return (double)GetValue(MinimumProperty); }
        set { SetValue(MinimumProperty, value); }
    }

    public double Maximum
    {
        get { return (double)GetValue(MaximumProperty); }
        set { SetValue(MaximumProperty, value); }
    }

    public double RangeMin
    {
        get { return (double)GetValue(RangeMinProperty); }
        set { SetValue(RangeMinProperty, value); }
    }

    public double RangeMax
    {
        get { return (double)GetValue(RangeMaxProperty); }
        set { SetValue(RangeMaxProperty, value); }
    }

    public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(MyRangeSlider), new PropertyMetadata(0.0));

    public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(MyRangeSlider), new PropertyMetadata(1.0));

    public static readonly DependencyProperty RangeMinProperty = DependencyProperty.Register("RangeMin", typeof(double), typeof(MyRangeSlider), new PropertyMetadata(0.0, OnRangeMinPropertyChanged));

    public static readonly DependencyProperty RangeMaxProperty = DependencyProperty.Register("RangeMax", typeof(double), typeof(MyRangeSlider), new PropertyMetadata(1.0, OnRangeMaxPropertyChanged));

    public MyRangeSlider()
    {
        this.InitializeComponent();
    }

    private static void OnRangeMinPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var slider = (MyRangeSlider)d;
        var newValue = (double)e.NewValue;

        if (newValue < slider.Minimum)
        {
            slider.RangeMin = slider.Minimum;
        }
        else if (newValue > slider.Maximum)
        {
            slider.RangeMin = slider.Maximum;
        }
        else
        {
            slider.RangeMin = newValue;
        }

        if (slider.RangeMin > slider.RangeMax)
        {
            slider.RangeMax = slider.RangeMin;
        }

        slider.UpdateMinThumb(slider.RangeMin);
    }

    private static void OnRangeMaxPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var slider = (MyRangeSlider)d;
        var newValue = (double)e.NewValue;

        if (newValue < slider.Minimum)
        {
            slider.RangeMax = slider.Minimum;
        }
        else if (newValue > slider.Maximum)
        {
            slider.RangeMax = slider.Maximum;
        }
        else
        {
            slider.RangeMax = newValue;
        }

        if (slider.RangeMax < slider.RangeMin)
        {
            slider.RangeMin = slider.RangeMax;
        }

        slider.UpdateMaxThumb(slider.RangeMax);
    }

    public void UpdateMinThumb(double min, bool update = false)
    {
        if (ContainerCanvas != null)
        {
            if (update || !MinThumb.IsDragging)
            {
                var relativeLeft = ((min - Minimum) / (Maximum - Minimum)) * ContainerCanvas.ActualWidth;

                Canvas.SetLeft(MinThumb, relativeLeft);
                Canvas.SetLeft(ActiveRectangle, relativeLeft);

                ActiveRectangle.Width = (RangeMax - min) / (Maximum - Minimum) * ContainerCanvas.ActualWidth;
            }
        }
    }

    public void UpdateMaxThumb(double max, bool update = false)
    {
        if (ContainerCanvas != null)
        {
            if (update || !MaxThumb.IsDragging)
            {
                var relativeRight = (max - Minimum) / (Maximum - Minimum) * ContainerCanvas.ActualWidth;

                Canvas.SetLeft(MaxThumb, relativeRight);

                ActiveRectangle.Width = (max - RangeMin) / (Maximum - Minimum) * ContainerCanvas.ActualWidth;
            }
        }
    }

    private void ContainerCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        var relativeLeft = ((RangeMin - Minimum) / (Maximum - Minimum)) * ContainerCanvas.ActualWidth;
        var relativeRight = (RangeMax - Minimum) / (Maximum - Minimum) * ContainerCanvas.ActualWidth;

        Canvas.SetLeft(MinThumb, relativeLeft);
        Canvas.SetLeft(ActiveRectangle, relativeLeft);
        Canvas.SetLeft(MaxThumb, relativeRight);

        ActiveRectangle.Width = (RangeMax - RangeMin) / (Maximum - Minimum) * ContainerCanvas.ActualWidth;
    }

    private void MinThumb_DragDelta(object sender, DragDeltaEventArgs e)
    {
        var min = DragThumb(MinThumb, 0, Canvas.GetLeft(MaxThumb), e.HorizontalChange);
        UpdateMinThumb(min, true);
        RangeMin = Math.Round(min);
    }

    private void MaxThumb_DragDelta(object sender, DragDeltaEventArgs e)
    {
        var max = DragThumb(MaxThumb, Canvas.GetLeft(MinThumb), ContainerCanvas.ActualWidth, e.HorizontalChange);
        UpdateMaxThumb(max, true);
        RangeMax = Math.Round(max);
    }

    private double DragThumb(Thumb thumb, double min, double max, double offset)
    {
        var currentPos = Canvas.GetLeft(thumb);
        var nextPos = currentPos + offset;

        nextPos = Math.Max(min, nextPos);
        nextPos = Math.Min(max, nextPos);

        return (Minimum + (nextPos / ContainerCanvas.ActualWidth) * (Maximum - Minimum));
    }

    private void MinThumb_DragCompleted(object sender, DragCompletedEventArgs e)
    {
        UpdateMinThumb(RangeMin);
        Canvas.SetZIndex(MinThumb, 10);
        Canvas.SetZIndex(MaxThumb, 0);
    }

    private void MaxThumb_DragCompleted(object sender, DragCompletedEventArgs e)
    {
        UpdateMaxThumb(RangeMax);
        Canvas.SetZIndex(MinThumb, 0);
        Canvas.SetZIndex(MaxThumb, 10);
    }
}

然后我可以像下面这样使用MyRangeSlider:

Then I can use MyRangeSlider like following:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="auto" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="auto" />
    </Grid.ColumnDefinitions>
    <TextBox HorizontalAlignment="Center" FontSize="20" Text="{Binding RangeMin, ElementName=RangeSlider, Mode=TwoWay}" />
    <local:MyRangeSlider x:Name="RangeSlider"
                         Grid.Column="1"
                         Maximum="100"
                         Minimum="0"
                         RangeMax="80"
                         RangeMin="20" />
    <TextBox Grid.Column="2"
             HorizontalAlignment="Center"
             FontSize="20"
             Text="{Binding RangeMax,
                            ElementName=RangeSlider,
                            Mode=TwoWay}" />
</Grid>

它看起来像:
这是一个简单的示例,您可以对其进行编辑以满足您的要求.并且,如果要创建自定义控件,可以参考

And it looks like:
This is a simple sample, you can edit it to meet your requirement. And if you want to create a custom control, you can refer to Building a custom control using XAML and C#. Although this article is for Windows 8 XAML platform, but UWP is the same.