博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
New UWP Community Toolkit - RangeSelector
阅读量:5763 次
发布时间:2019-06-18

本文共 5882 字,大约阅读时间需要 19 分钟。

概述

前面 New UWP Community Toolkit 文章中,我们对 V2.2.0 版本的重要更新做了简单回顾,其中简单介绍了 RangeSelector,本篇我们结合代码详细讲解一下 RangeSelector 相关功能。

RangeSelector 是一种范围选择控件,有两个滑块控件,允许用户在控件的取值范围内选择一个子区间范围。在实际应用开发中 RangeSelector 也有着非常广泛的应用,例如筛选时的价格区间选择等等。我们来看一下官方示例中的展示:

Source: 

Doc: 

Namespace: Microsoft.Toolkit.Uwp.UI.Controls; Nuget: Microsoft.Toolkit.Uwp.UI.Controls;

 

开发过程

代码分析

先来看看 RangeSelector 的结构组成:

  • RangeChangedEventArgs.cs - 范围改变处理事件传入的参数类,包含了 oldValue,newValue 和 ChangedRangeProperty(标志 min 和 max 两个区间值是否改变)
  • RangeSelector.cs - RangeSelector 的控件定义和事件处理类
  • RangeSelector.xaml - RangeSelector 的样式文件

下面来看一下几个主要类中的主要代码实现,因为篇幅关系,我们只摘录部分关键代码实现:

1.  RangeSelector.xaml

 RangeSelector.xaml 是 RangeSelector 控件的样式文件,我们看到 Template 部分,由一个背景 Border OutOfRangeContentContainer,两个选择滑块 MinThumb 和 MaxThumb,以及显示当前范围的矩形 ActiveRectangle 组成;再看 VisualStateManager,我们截取了一部分,在 MinPressed 发生时,MinThumb 被高亮显示,同理其他状态发生时也会有对应的视觉状态发生。 

                                
...
...

2. RangeSelector.cs

我们先看看 RangeSelector 类的组成: 

 

先来看看类中的依赖属性:

  • Minimum - 控件允许选择范围的最小值,默认是 0.0,修改时触发 MinimumChangedCallback
  • Maximum - 控件允许选择范围的最大值,默认是 1.0,修改时触发 MaximumChangedCallback
  • RangeMin - 控件实际选择范围的最小值,默认是 0.0,修改时触发 RangeMinChangedCallback
  • RangeMax - 控件实际选择范围的最大值,默认是 1.0,修改时触发 RangeMaxChangedCallback
  • IsTouchOptimized - 触摸优化的标志,默认是 false,修改时触发 IsTouchOptimizedChangedCallback
  • StepFrequency - 每次调整范围时的步长,默认是 1.0

我们在其中挑出有代表性的方法详细看一下:

① MinimumChangedCallback(d, e)

允许范围最小值调整的回调方法,最大值对应的方法功能类似;当最小值调整后的 newValue 大于等于旧的最大值时,对最大值重新设置为 newValue + 0.01;当 newValue 大于等于实际范围最小值时,把实际最小值设置为 newValue,当 newValue 大于等于实际范围最大值时,把实际最大值也设置为 newValue;最后如果 newValue 小于 oldValue 时,需要同步滑块的位置;

private static void MinimumChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e){    var rangeSelector = d as RangeSelector;    if (rangeSelector == null || !rangeSelector._valuesAssigned)    {        return;    }    var newValue = (double)e.NewValue;    var oldValue = (double)e.OldValue;    if (rangeSelector.Maximum < newValue)    {        rangeSelector.Maximum = newValue + Epsilon;    }    if (rangeSelector.RangeMin < newValue)    {        rangeSelector.RangeMin = newValue;    }    if (rangeSelector.RangeMax < newValue)    {        rangeSelector.RangeMax = newValue;    }    if (newValue < oldValue)    {        rangeSelector.SyncThumbs();    }}

② RangeMinChangedCallback(d, e)

实际范围最小值调整的回调方法,最大值对应的方法功能类似;根据步长来对 newValue 做矫正,比如 oldValue = 0.0,newValue = 0.11,步长 0.1,那么 newValue 会调整为 0.1;然后是对 newValue 超出允许选择范围时的边界处理;最后实际选择范围修改时,需要同步调整显示实际范围的矩形控件的状态;

private static void RangeMinChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e){    var rangeSelector = d as RangeSelector;    if (rangeSelector == null)    {        return;    }    rangeSelector._minSet = true;    if (!rangeSelector._valuesAssigned)    {        return;    }    var newValue = (double)e.NewValue;    rangeSelector.RangeMinToStepFrequency();    if (rangeSelector._valuesAssigned)    {        if (newValue < rangeSelector.Minimum)        {            rangeSelector.RangeMin = rangeSelector.Minimum;            return;        }        if (newValue > rangeSelector.Maximum)        {            rangeSelector.RangeMin = rangeSelector.Maximum;            return;        }        rangeSelector.SyncActiveRectangle();        if (newValue > rangeSelector.RangeMax)        {            rangeSelector.RangeMax = newValue;        }    }    else    {        rangeSelector.SyncActiveRectangle();    }}

③ IsTouchOptimizedChangedCallback(d, e)

当触摸优化变化时,控件也会做出变化,实际处理方法是 ArrangeForTouch();我们看到,在触摸优化后,滑块的宽高被设置为 44,对应的范围显示也会变大;而在非触摸优化时,控件整体会变小,变为鼠标点击时的样式;因为实现了触摸优化,所以我们可以根据当前设备是否是平板模式,来决定控件的显示状态,非常有用。

private void ArrangeForTouch(){    if (_containerCanvas == null)    {        return;    }    if (IsTouchOptimized)    {        ...        if (_minThumb != null)        {            _minThumb.Width = _minThumb.Height = 44;            _minThumb.Margin = new Thickness(-20, 0, 0, 0);        }        ...    }    else    {        ...        if (_minThumb != null)        {            _minThumb.Width = 8;            _minThumb.Height = 24;            _minThumb.Margin = new Thickness(-8, 0, 0, 0);        }        ...    }}

下面的几个方法,主要处理的是 rangeMin 和 rangeMax 两个滑块的拖拽事件,我们还是只看 min 对应的处理,max 处理类似:

根据当前滑块拖拽后的位置,来修改实际范围最小值;计算方式就是根据允许范围区间,控件实际宽度,以及当前位置距离最小值的距离,来计算出比例;

private void MinThumb_DragDelta(object sender, DragDeltaEventArgs e){    _absolutePosition += e.HorizontalChange;    RangeMin = DragThumb(_minThumb, 0, Canvas.GetLeft(_maxThumb), _absolutePosition);}private double DragThumb(Thumb thumb, double min, double max, double nextPos){    nextPos = Math.Max(min, nextPos);    nextPos = Math.Min(max, nextPos);    Canvas.SetLeft(thumb, nextPos);    return Minimum + ((nextPos / _containerCanvas.ActualWidth) * (Maximum - Minimum));}

而在滑块拖拽开始和结束时,以及可用状态变化时,也会触发对应的 VisualStateManager 的 state 来调整控件视觉显示状态;

 

调用示例

我们定义了一个 RangeSelector 控件,在左右两侧显示当前选择范围的最小值和最大值,而控件的可选范围区间是 0~100,可以看到示例运行图的显示:

 

总结

到这里我们就把 UWP Community Toolkit 中的 RangeSelector 控件的源代码实现过程和简单的调用示例讲解完成了,希望能对大家更好的理解和使用这个控件有所帮助,大家也可以在实际应用中,编写更丰富的控件样式,或者更特殊的范围选择,比如环形等。欢迎大家多多交流,谢谢!

最后,再跟大家安利一下 UWPCommunityToolkit 的官方微博:大家可以通过微博关注最新动态。

衷心感谢 UWPCommunityToolkit 的作者们杰出的工作,Thank you so much, UWPCommunityToolkit authors!!!

 

转载地址:http://iqgkx.baihongyu.com/

你可能感兴趣的文章