Skip to content

Commit e4050fa

Browse files
Merge branch 'master' into dev/stringextensions-a11y
2 parents 343e21b + 607798b commit e4050fa

File tree

9 files changed

+730
-602
lines changed

9 files changed

+730
-602
lines changed

Microsoft.Toolkit.Uwp.SampleApp/SamplePages/RangeSelector/RangeSelectorCode.bind

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<TextBlock Grid.Column="0"
2222
HorizontalAlignment="Left"
2323
VerticalAlignment="Center"
24-
Text="{Binding RangeMin, ElementName=RangeSelectorControl, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:0.##}'}" />
24+
Text="{Binding RangeStart, ElementName=RangeSelectorControl, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:0.##}'}" />
2525
<controls:RangeSelector x:Name="RangeSelectorControl"
2626
Grid.Column="1"
2727
Minimum="@[Minimum:Slider:0:0-100]@"
@@ -30,7 +30,7 @@
3030
<TextBlock Grid.Column="2"
3131
HorizontalAlignment="Right"
3232
VerticalAlignment="Center"
33-
Text="{Binding RangeMax, ElementName=RangeSelectorControl, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:0.##}'}" />
33+
Text="{Binding RangeEnd, ElementName=RangeSelectorControl, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:0.##}'}" />
3434
</Grid>
3535
</Grid>
3636
</Page>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using Windows.UI.Xaml.Controls;
7+
using Windows.UI.Xaml.Controls.Primitives;
8+
9+
namespace Microsoft.Toolkit.Uwp.UI.Controls
10+
{
11+
/// <summary>
12+
/// RangeSelector is a "double slider" control for range values.
13+
/// </summary>
14+
public partial class RangeSelector : Control
15+
{
16+
/// <summary>
17+
/// Event raised when lower or upper range thumbs start being dragged.
18+
/// </summary>
19+
public event DragStartedEventHandler ThumbDragStarted;
20+
21+
/// <summary>
22+
/// Event raised when lower or upper range thumbs end being dragged.
23+
/// </summary>
24+
public event DragCompletedEventHandler ThumbDragCompleted;
25+
26+
/// <summary>
27+
/// Event raised when lower or upper range values are changed.
28+
/// </summary>
29+
public event EventHandler<RangeChangedEventArgs> ValueChanged;
30+
31+
/// <summary>
32+
/// Called before the <see cref="ThumbDragStarted"/> event occurs.
33+
/// </summary>
34+
/// <param name="e">Event data for the event.</param>
35+
protected virtual void OnThumbDragStarted(DragStartedEventArgs e)
36+
{
37+
ThumbDragStarted?.Invoke(this, e);
38+
}
39+
40+
/// <summary>
41+
/// Called before the <see cref="ThumbDragCompleted"/> event occurs.
42+
/// </summary>
43+
/// <param name="e">Event data for the event.</param>
44+
protected virtual void OnThumbDragCompleted(DragCompletedEventArgs e)
45+
{
46+
ThumbDragCompleted?.Invoke(this, e);
47+
}
48+
49+
/// <summary>
50+
/// Called before the <see cref="ValueChanged"/> event occurs.
51+
/// </summary>
52+
/// <param name="e"><see cref="RangeChangedEventArgs"/> event data for the event.</param>
53+
protected virtual void OnValueChanged(RangeChangedEventArgs e)
54+
{
55+
ValueChanged?.Invoke(this, e);
56+
}
57+
}
58+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using Windows.Foundation;
7+
using Windows.UI.Xaml;
8+
using Windows.UI.Xaml.Controls;
9+
using Windows.UI.Xaml.Controls.Primitives;
10+
11+
namespace Microsoft.Toolkit.Uwp.UI.Controls
12+
{
13+
/// <summary>
14+
/// RangeSelector is a "double slider" control for range values.
15+
/// </summary>
16+
public partial class RangeSelector : Control
17+
{
18+
private void MinThumb_DragDelta(object sender, DragDeltaEventArgs e)
19+
{
20+
_absolutePosition += e.HorizontalChange;
21+
22+
RangeStart = DragThumb(_minThumb, 0, Canvas.GetLeft(_maxThumb), _absolutePosition);
23+
24+
if (_toolTipText != null)
25+
{
26+
UpdateToolTipText(this, _toolTipText, RangeStart);
27+
}
28+
}
29+
30+
private void MaxThumb_DragDelta(object sender, DragDeltaEventArgs e)
31+
{
32+
_absolutePosition += e.HorizontalChange;
33+
34+
RangeEnd = DragThumb(_maxThumb, Canvas.GetLeft(_minThumb), DragWidth(), _absolutePosition);
35+
36+
if (_toolTipText != null)
37+
{
38+
UpdateToolTipText(this, _toolTipText, RangeEnd);
39+
}
40+
}
41+
42+
private void MinThumb_DragStarted(object sender, DragStartedEventArgs e)
43+
{
44+
OnThumbDragStarted(e);
45+
Thumb_DragStarted(_minThumb);
46+
}
47+
48+
private void MaxThumb_DragStarted(object sender, DragStartedEventArgs e)
49+
{
50+
OnThumbDragStarted(e);
51+
Thumb_DragStarted(_maxThumb);
52+
}
53+
54+
private void Thumb_DragCompleted(object sender, DragCompletedEventArgs e)
55+
{
56+
OnThumbDragCompleted(e);
57+
OnValueChanged(sender.Equals(_minThumb) ? new RangeChangedEventArgs(_oldValue, RangeStart, RangeSelectorProperty.MinimumValue) : new RangeChangedEventArgs(_oldValue, RangeEnd, RangeSelectorProperty.MaximumValue));
58+
SyncThumbs();
59+
60+
if (_toolTip != null)
61+
{
62+
_toolTip.Visibility = Visibility.Collapsed;
63+
}
64+
65+
VisualStateManager.GoToState(this, "Normal", true);
66+
}
67+
68+
private double DragWidth()
69+
{
70+
return _containerCanvas.ActualWidth - _maxThumb.Width;
71+
}
72+
73+
private double DragThumb(Thumb thumb, double min, double max, double nextPos)
74+
{
75+
nextPos = Math.Max(min, nextPos);
76+
nextPos = Math.Min(max, nextPos);
77+
78+
Canvas.SetLeft(thumb, nextPos);
79+
80+
if (_toolTipText != null && _toolTip != null)
81+
{
82+
var thumbCenter = nextPos + (thumb.Width / 2);
83+
_toolTip.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
84+
var ttWidth = _toolTip.ActualWidth / 2;
85+
86+
Canvas.SetLeft(_toolTip, thumbCenter - ttWidth);
87+
}
88+
89+
return Minimum + ((nextPos / DragWidth()) * (Maximum - Minimum));
90+
}
91+
92+
private void Thumb_DragStarted(Thumb thumb)
93+
{
94+
var useMin = thumb == _minThumb;
95+
var otherThumb = useMin ? _maxThumb : _minThumb;
96+
97+
_absolutePosition = Canvas.GetLeft(thumb);
98+
Canvas.SetZIndex(thumb, 10);
99+
Canvas.SetZIndex(otherThumb, 0);
100+
_oldValue = RangeStart;
101+
102+
if (_toolTipText != null && _toolTip != null)
103+
{
104+
_toolTip.Visibility = Visibility.Visible;
105+
var thumbCenter = _absolutePosition + (thumb.Width / 2);
106+
_toolTip.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
107+
var ttWidth = _toolTip.ActualWidth / 2;
108+
Canvas.SetLeft(_toolTip, thumbCenter - ttWidth);
109+
110+
UpdateToolTipText(this, _toolTipText, useMin ? RangeStart : RangeEnd);
111+
}
112+
113+
VisualStateManager.GoToState(this, useMin ? "MinPressed" : "MaxPressed", true);
114+
}
115+
}
116+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Windows.System;
6+
using Windows.UI.Xaml;
7+
using Windows.UI.Xaml.Controls;
8+
using Windows.UI.Xaml.Input;
9+
10+
namespace Microsoft.Toolkit.Uwp.UI.Controls
11+
{
12+
/// <summary>
13+
/// RangeSelector is a "double slider" control for range values.
14+
/// </summary>
15+
public partial class RangeSelector : Control
16+
{
17+
private readonly DispatcherQueueTimer keyDebounceTimer = DispatcherQueue.GetForCurrentThread().CreateTimer();
18+
19+
private void MinThumb_KeyDown(object sender, KeyRoutedEventArgs e)
20+
{
21+
switch (e.Key)
22+
{
23+
case VirtualKey.Left:
24+
RangeStart -= StepFrequency;
25+
SyncThumbs(fromMinKeyDown: true);
26+
if (_toolTip != null)
27+
{
28+
_toolTip.Visibility = Visibility.Visible;
29+
}
30+
31+
e.Handled = true;
32+
break;
33+
case VirtualKey.Right:
34+
RangeStart += StepFrequency;
35+
SyncThumbs(fromMinKeyDown: true);
36+
if (_toolTip != null)
37+
{
38+
_toolTip.Visibility = Visibility.Visible;
39+
}
40+
41+
e.Handled = true;
42+
break;
43+
}
44+
}
45+
46+
private void MaxThumb_KeyDown(object sender, KeyRoutedEventArgs e)
47+
{
48+
switch (e.Key)
49+
{
50+
case VirtualKey.Left:
51+
RangeEnd -= StepFrequency;
52+
SyncThumbs(fromMaxKeyDown: true);
53+
if (_toolTip != null)
54+
{
55+
_toolTip.Visibility = Visibility.Visible;
56+
}
57+
58+
e.Handled = true;
59+
break;
60+
case VirtualKey.Right:
61+
RangeEnd += StepFrequency;
62+
SyncThumbs(fromMaxKeyDown: true);
63+
if (_toolTip != null)
64+
{
65+
_toolTip.Visibility = Visibility.Visible;
66+
}
67+
68+
e.Handled = true;
69+
break;
70+
}
71+
}
72+
73+
private void Thumb_KeyUp(object sender, KeyRoutedEventArgs e)
74+
{
75+
switch (e.Key)
76+
{
77+
case VirtualKey.Left:
78+
case VirtualKey.Right:
79+
if (_toolTip != null)
80+
{
81+
keyDebounceTimer.Debounce(
82+
() => _toolTip.Visibility = Visibility.Collapsed,
83+
TimeToHideToolTipOnKeyUp);
84+
}
85+
86+
e.Handled = true;
87+
break;
88+
}
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)