通用 Windows (UWP) 范围滑块
Posted
技术标签:
【中文标题】通用 Windows (UWP) 范围滑块【英文标题】:Universal Windows (UWP) Range Slider 【发布时间】:2016-08-01 10:47:57 【问题描述】:我想在 UWP 中创建 范围滑块。我没有找到任何例子。只有单个滑块,但我希望它像 。
有人知道我该怎么做吗?请帮帮我。
【问题讨论】:
【参考方案1】:要在 UWP 中创建范围滑块,我们可以创建自定义控件或使用UserControl
。这里我以UserControl
为例:
首先,我在我的项目中添加一个名为“MyRangeSlider”的 UserControl。
在 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
,如下所示:
<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>
它看起来像: 这是一个简单的示例,您可以对其进行编辑以满足您的要求。而如果要创建自定义控件,可以参考Building a custom control using XAML and C#。虽然这篇文章是针对Windows 8 XAML平台的,但是UWP也是一样的。
【讨论】:
以上是关于通用 Windows (UWP) 范围滑块的主要内容,如果未能解决你的问题,请参考以下文章
制作 | UWP :: 使用 Cmake 构建通用 Windows 应用程序
详解 UWP (通用 Windows 平台) 中的两种 HttpClient API
如何为通用 Windows 平台(UWP)应用程序创建 .appx 包?