原文:数值范围选择控件RangeSlider

RangeSlider控件用于在一个指定上下限的范围中选择一个数值范围,因此该控件的Maximum和Minimum属性用于指定上下限;而SelectionStart和SelectionEnd用于指定选择的范围,还有一个Change属性用于指定SelectionStart和SelectionEnd的最小变化值。运行效果如下图所示。默认样式很难看,不过定制一个漂亮的样式很简单。

  

 

以下是控件的默认样式:

<Style TargetType="{x:Type
local:RangeSlider}">

        <Setter Property="Template">

            <Setter.Value>

                <ControlTemplate TargetType="{x:Type
local:RangeSlider}">

                    <Border BorderBrush="{TemplateBinding
BorderBrush}"

                            BorderThickness="{TemplateBinding BorderThickness}"

                            Background="{TemplateBinding Background}"

                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">

                        <Grid Name="PART_GridContainerName">

                            <Grid.ColumnDefinitions>

                               
<ColumnDefinition/>

                               
<ColumnDefinition/>

                               
<ColumnDefinition/>

                            </Grid.ColumnDefinitions>

                            <RepeatButton Grid.Column="0"
Command="{x:Static local:RangeSlider.MoveBackward}"/>

                            <RepeatButton Grid.Column="2"
Command="{x:Static local:RangeSlider.MoveForward}"/>

                            <Grid Grid.Column="1">

                               
<Thumb Name="PART_LeftThumb" IsTabStop="False"
Cursor="SizeWE" Width="5" Margin="-5 0 00" HorizontalAlignment="Left"/>

                               
<Thumb Name="PART_CenterThumb" IsTabStop="False"
Cursor="ScrollAll" MinWidth="5"/>

                               
<Thumb Name="PART_RightThumb" IsTabStop="False"
Cursor="SizeWE" Width="5" Margin="0 0 -50" HorizontalAlignment="Right"/>

                            </Grid>

                        </Grid>

                    </Border>

                </ControlTemplate>

            </Setter.Value>

        </Setter>

    </Style>

从控件的样式中可以看出,三个Thumb分别支持拖动改变开始值,结束值和同时改变两个值。两个RepeatButton支持按最小变化值同时改变开始值和结束值;按下Ctl键和左右箭头可达到相同的目的。

RangeSlider控件还实现了SelectedRangeChanged路由事件,这样就可以在SelectionStart和SelectionEnd改变的时候发出事件通知。

RangeSlider控件还支持命令;也就是说它实现了ICommandSource接口,这样就可以和MVVM模式很好的结合起来。剩下也没什么好说的了,代码贴上:

using System;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

usingSystem.Windows.Controls;

usingSystem.Windows;

usingSystem.Windows.Input;

usingSystem.Windows.Controls.Primitives;

usingSystem.ComponentModel;

 

namespace MySolution.Controls

{

    [TemplatePart(Name = GridContainerName, Type =
typeof(Grid))]

    [TemplatePart(Name = LeftThumbName, Type =
typeof(Thumb))]

    [TemplatePart(Name = CenterThumbName, Type =
typeof(Thumb))]

    [TemplatePart(Name = RightThumbName, Type =
typeof(Thumb))]

    public
class RangeSlider :
Control,ICommandSource

    {

       static RangeSlider()

       {

           DefaultStyleKeyProperty.OverrideMetadata(typeof(RangeSlider),
new FrameworkPropertyMetadata(typeof(RangeSlider)));

       }

 

        #region PartNames

 

       private
conststring LeftThumbName =
"PART_LeftThumb";

       private
conststring CenterThumbName =
"PART_CenterThumb";

       private
conststring RightThumbName =
"PART_RightThumb";

       private
conststring GridContainerName =
"PART_GridContainerName";

 

        #endregion

 

        #region Minimum

 

        public
long Minimum

       {

           get {
return(long)GetValue(MinimumProperty); }

           set { SetValue(MinimumProperty,
value); }

       }

 

       public
staticreadonly
DependencyPropertyMinimumProperty =

         DependencyProperty.Register("Minimum",
typeof(long),
typeof(RangeSlider),

         new
FrameworkPropertyMetadata(0L,OnMinimumChanged));

 

       private
staticvoid OnMinimumChanged(DependencyObjectsender,
DependencyPropertyChangedEventArgse)

       {

           RangeSlider slider = sender
as RangeSlider;

           slider.CoerceValue(MaximumProperty);

           slider.CoerceValue(SelectionStartProperty);

           slider.CoerceValue(SelectionEndProperty);

           slider.Relayout();

       }

 

        #endregion

 

        #region Maximum

 

       public
longMaximum

       {

           get {
return(long)GetValue(MaximumProperty); }

           set { SetValue(MaximumProperty,
value); }

       }

 

       public
staticreadonly
DependencyPropertyMaximumProperty =

         DependencyProperty.Register("Maximum",
typeof(long),
typeof(RangeSlider),

         new
FrameworkPropertyMetadata(100L,OnMaximumChanged, CoerceMaximum));

 

       private
staticvoid OnMaximumChanged(DependencyObjectsender,
DependencyPropertyChangedEventArgse)

       {

           RangeSlider slider = sender
as RangeSlider;

           slider.CoerceValue(SelectionStartProperty);

           slider.CoerceValue(SelectionEndProperty);

           slider.Relayout();

       }

 

       private
staticobject CoerceMaximum(DependencyObjectsender,
object baseValue)

       {

           RangeSlider slider = sender
as RangeSlider;

           long value = (long)baseValue;

 

           if (value < slider.Minimum + 1)

           {

                returnslider.Minimum + 1;

           }

 

           return baseValue;

       }

 

        #endregion

 

        #regionSelectionStart

 

       public
longSelectionStart

       {

           get {
return(long)GetValue(SelectionStartProperty); }

           set { SetValue(SelectionStartProperty,
value); }

       }

 

       public
staticreadonly
DependencyPropertySelectionStartProperty =

         DependencyProperty.Register("SelectionStart",
typeof(long),
typeof(RangeSlider),

         new
FrameworkPropertyMetadata(0L,OnSelectionStartChanged, CoerceSelectionStart));

 

       private
staticvoid OnSelectionStartChanged(DependencyObject sender,
DependencyPropertyChangedEventArgse)

       {

           RangeSlider slider = sender
as RangeSlider;

           slider.CoerceValue(SelectionEndProperty);

           slider.Relayout();

       }

 

       private
staticobject CoerceSelectionStart(DependencyObject sender,
objectbaseValue)

       {

           RangeSlider slider = sender
as RangeSlider;

           long value = (long)baseValue;

 

           if (slider.SelectionEnd >=slider.Minimum && slider.SelectionEnd <= slider.Maximum)

           {

                if(value > slider.SelectionEnd)

                {

                    returnslider.SelectionEnd;

                }

           }

 

           if (value < slider.Minimum)

           {

                returnslider.Minimum;

           }

 

           if (value > slider.Maximum)

           {

                returnslider.Maximum;

           }

 

           return baseValue;

       }

 

        #endregion

 

        #regionSelectionEnd

 

       public
longSelectionEnd

       {

           get {
return(long)GetValue(SelectionEndProperty); }

           set { SetValue(SelectionEndProperty,
value); }

       }

 

       public
staticreadonly
DependencyPropertySelectionEndProperty =

         DependencyProperty.Register("SelectionEnd",
typeof(long),
typeof(RangeSlider),

         new
FrameworkPropertyMetadata(10L,OnSelectionEndChanged, CoerceSelectionEnd));

 

       private
staticvoid OnSelectionEndChanged(DependencyObject sender,
DependencyPropertyChangedEventArgse)

       {

           RangeSlider slider = sender
as RangeSlider;

           slider.CoerceValue(SelectionStartProperty);

           slider.Relayout();

       }

 

       private
staticobject CoerceSelectionEnd(DependencyObject sender,
objectbaseValue)

       {

           RangeSlider slider = sender
as RangeSlider;

           long value = (long)baseValue;

 

           if (slider.SelectionStart >=slider.Minimum && slider.SelectionStart <= slider.Maximum)

           {

                if(value < slider.SelectionStart)

                {

                    returnslider.SelectionStart;

                }

           }

 

           if (value < slider.Minimum)

           {

                returnslider.Minimum;

           }

 

           if (value > slider.Maximum)

           {

                returnslider.Maximum;

           }

 

           returnbaseValue;

       }

 

        #endregion

 

        #region Change

 

       public
longChange

       {

           get {
return(long)GetValue(ChangeProperty); }

           set { SetValue(ChangeProperty,
value); }

       }

 

       public
staticreadonly
DependencyPropertyChangeProperty =

         DependencyProperty.Register("Change",
typeof(long),
typeof(RangeSlider),

         new
FrameworkPropertyMetadata(1L),ValidateChange);

 

       private
staticbool ValidateChange(objectvalue)

        {

           return (long)value!= 0;

       }

 

        #endregion

 

        #region RoutedEvents

 

       ///<summary>

       /// Eventraised whenever the selected range is changed

       ///</summary>

       public
staticreadonly
RoutedEventSelectionChangedEvent = EventManager.RegisterRoutedEvent(

           "SelectionChangedEvent",

           RoutingStrategy.Bubble,

           typeof(EventHandler<RangeSelectionChangedEventArgs>),

           typeof(RangeSlider));

 

       ///<summary>

       /// Eventraised whenever the selected range is changed

       ///</summary>

       public
eventEventHandler<RangeSelectionChangedEventArgs>SelectedRangeChanged

       {

           add { AddHandler(SelectionChangedEvent,
value); }

           remove {RemoveHandler(SelectionChangedEvent,
value); }

       }

 

       private
voidOnSelectedRangeChanged(RangeSelectionChangedEventArgse)

       {

           e.RoutedEvent = SelectionChangedEvent;

           RaiseEvent(e);

 

           ExecuteCommand();

       }

 

       private
voidExecuteCommand()

       {

           if (Command !=
null)

           {

                RoutedCommandcommand = Command
as RoutedCommand;

 

                if(command !=
null)

                {

                   command.Execute(CommandParameter,CommandTarget);

                }

                else

                {

                   Command.Execute(CommandParameter);

                }

           }

       }

 

        #endregion

 

        #regionCommands

 

        #region Commanddeclaration

 

       ///<summary>

       /// Command tomove back the selection

       ///</summary>

       public
staticRoutedUICommand MoveBackward =

         new
RoutedUICommand("Move Backward",
"MoveBackward", typeof(RangeSlider),

           new
InputGestureCollection(new
InputGesture[]{ new
KeyGesture(Key.Left,
ModifierKeys.Control)}));

 

       ///<summary>

       /// Command tomove forward the selection

       ///</summary>

       public
staticRoutedUICommand MoveForward =

         new
RoutedUICommand("Move Forward",
"MoveForward",typeof(RangeSlider),

           new
InputGestureCollection(new
InputGesture[]{ new
KeyGesture(Key.Right,
ModifierKeys.Control)}));

 

        #endregion

 

        #region CommandHandlers

 

       private
voidMoveBackwardHandler(object sender,
ExecutedRoutedEventArgs e)

       {

           MoveSelection(-Change);

       }

 

       private
voidMoveForwardHandler(object sender,
ExecutedRoutedEventArgs e)

       {

           MoveSelection(Change);

       }

 

        #endregion

 

        #endregion

 

        #regionConstructor

 

       public RangeSlider()

       {

           CommandBindings.Add(new
CommandBinding(MoveBackward,MoveBackwardHandler));

           CommandBindings.Add(new
CommandBinding(MoveForward, MoveForwardHandler));

       }

 

        #endregion

 

        #region Fields

 

       private
Thumb_centerThumb;

       private
Thumb_leftThumb;

       private
Thumb_rightThumb;

       private
Grid_gridContainer;

 

        #endregion

 

       public
overridevoid OnApplyTemplate()

       {

           base.OnApplyTemplate();

 

           _centerThumb = Template.FindName(CenterThumbName,
this) as Thumb;

           _leftThumb = Template.FindName(LeftThumbName,
this)as Thumb;

           _rightThumb = Template.FindName(RightThumbName,
this)as Thumb;

           _gridContainer = Template.FindName(GridContainerName,
this) as Grid;

 

           _leftThumb.DragDelta += DragSelectionStart;

           _centerThumb.DragDelta += DragSelection;

           _rightThumb.DragDelta += DragSelectionEnd;

 

           Relayout();

       }

 

       private
voidRelayout()

       {

           if (_gridContainer ==
null || SelectionEnd - SelectionStart < 0)

           {

                return;

           }

 

           double colWidth1 = SelectionStart -Minimum;

           double colWidth2 = SelectionEnd -SelectionStart;

           double colWidth3 = Maximum -SelectionEnd;

 

           _gridContainer.ColumnDefinitions[0].Width =
newGridLength(colWidth1,
GridUnitType.Star);

           _gridContainer.ColumnDefinitions[1].Width =
newGridLength(colWidth2,
GridUnitType.Star);

           _gridContainer.ColumnDefinitions[2].Width =
newGridLength(colWidth3,
GridUnitType.Star);

 

           OnSelectedRangeChanged(new
RangeSelectionChangedEventArgs(SelectionStart,SelectionEnd));

       }

 

        #regionDragHandlers

 

       private
voidDragSelection(object sender,
DragDeltaEventArgs e)

       {

           long offsetValue =GetNormalizedValue(e.HorizontalChange);

           MoveSelection(offsetValue);

       }

 

       private
voidMoveSelection(long offsetValue)

       {

           if (offsetValue < 0)

           {

                if(SelectionStart == Minimum)

                {

                    return;

                }

 

                longrange = SelectionEnd - SelectionStart;

                longnewValue = SelectionStart + offsetValue;

                SelectionStart = Math.Max(Minimum, newValue);

                SelectionEnd = SelectionStart +range;

           }

           else
if(offsetValue > 0)

           {

                if(SelectionEnd == Maximum)

                {

                    return;

                }

 

                longrange = SelectionEnd - SelectionStart;

                longnewValue = SelectionEnd + offsetValue;

                SelectionEnd = Math.Min(Maximum, newValue);

                SelectionStart = SelectionEnd -range;

           }

       }

 

       private
voidMoveSelectionStart(long offsetValue)

       {

           if (offsetValue < 0)

           {

                if(SelectionStart == Minimum)

               {

                    return;

                }

 

                longnewValue = SelectionStart + offsetValue;

                SelectionStart = Math.Max(Minimum, newValue);

           }

           else
if(offsetValue > 0)

           {

                longmax = SelectionEnd - Change;

                if(SelectionStart == max)

                {

                    return;

                }

 

                longnewValue = SelectionStart + offsetValue;

                SelectionStart = Math.Min(max, newValue);

           }

       }

 

       private
voidMoveSelectionEnd(long offsetValue)

       {

           if (offsetValue < 0)

           {

                longmin = SelectionStart + Change;

                if(SelectionEnd == min)

                {

                    return;

                }

 

                longnewValue = SelectionEnd + offsetValue;

                SelectionEnd = Math.Max(min, newValue);

           }

           else
if(offsetValue > 0)

           {

                if(SelectionEnd == Maximum)

                {

                    return;

                }

 

                longnewValue = SelectionEnd + offsetValue;

                SelectionEnd = Math.Min(Maximum, newValue);

           }

       }

 

        private
void DragSelectionEnd(objectsender,
DragDeltaEventArgs e)

       {

           long offsetValue =GetNormalizedValue(e.HorizontalChange);

           MoveSelectionEnd(offsetValue);

       }

 

       private
voidDragSelectionStart(object sender,
DragDeltaEventArgs e)

       {

           long offsetValue =GetNormalizedValue(e.HorizontalChange);

           MoveSelectionStart(offsetValue);

       }

 

        #endregion

 

        #region HelperMethod

 

       private
longGetNormalizedValue(double pixelLength)

       {

           long offsetValue = (long)((Maximum - Minimum) * (pixelLength /RenderSize.Width));

           long mod = offsetValue % Change;

 

           if (Math.Abs(mod)< Change / 2)

           {

               offsetValue = Math.Sign(offsetValue) * ((long)(Math.Abs(offsetValue) /Change)) * Change;

           }

           else

           {

                offsetValue = Math.Sign(offsetValue) * ((long)(Math.Abs(offsetValue) /Change) + 1) * Change;

            }

 

           return offsetValue;

       }

 

        #endregion

 

        #regionICommandSource Members

 

       public
staticreadonly
DependencyPropertyCommandProperty =

           DependencyProperty.Register("Command",
typeof(ICommand),
typeof(RangeSlider),
new PropertyMetadata(null,OnCommandChanged));

 

       public
staticreadonly
DependencyPropertyCommandParameterProperty =

           DependencyProperty.Register("CommandParameter",
typeof(object),
typeof(RangeSlider),new
FrameworkPropertyMetadata(null));

 

       public
staticreadonly
DependencyPropertyCommandTargetProperty =

           DependencyProperty.Register("CommandTarget",
typeof(IInputElement),
typeof(RangeSlider),new
FrameworkPropertyMetadata(null));

 

       public
objectCommandParameter

       {

           get {
return(object)GetValue(CommandParameterProperty); }

           set { SetValue(CommandParameterProperty,value); }

       }

 

       public
ICommandCommand

       {

           get {
return(ICommand)GetValue(CommandProperty); }

           set { SetValue(CommandProperty,
value); }

       }

 

       public
IInputElementCommandTarget

       {

           get {
return(IInputElement)GetValue(CommandTargetProperty);}

           set { SetValue(CommandTargetProperty,
value); }

       }

 

       private
staticvoid OnCommandChanged(DependencyObjectsender,
DependencyPropertyChangedEventArgse)

       {

           RangeSlider slider = sender
as RangeSlider;

           slider.OnCommandChanged(e.OldValue
as ICommand, e.NewValue
asICommand);

       }

 

       private
voidOnCommandChanged(ICommand oldCommand,
ICommand newCommand)

       {

           if (oldCommand !=
null)

           {

                oldCommand.CanExecuteChanged -=CanExecuteChanged;

           }

 

           if (newCommand !=
null)

           {

                newCommand.CanExecuteChanged +=CanExecuteChanged;

           }

       }

 

       private
voidCanExecuteChanged(object sender,
EventArgs e)

       {

           if (Command !=
null)

           {

                RoutedCommandcommand = Command
as RoutedCommand;

 

                if(command !=
null)

                {

                    IsEnabled = command.CanExecute(CommandParameter,CommandTarget);

                }

                else

                {

                    IsEnabled =Command.CanExecute(CommandParameter);

                }

           }

       }

 

        #endregion

    }

}

 

 

 

数值范围选择控件RangeSlider的更多相关文章

  1. 通用数据水平层级选择控件v0.70升级版使其支持jQuery v1.9.1

    升级原因:作者原来脚本支持的jquery版本太低了,查找了下资料,使得它能支持最新版本的jquery 备注说明:脚本代码源作者跟源文出处很难找,只能在此特感谢他的分享. 更新部分: 1.新版本不再支持 ...

  2. Windows Phone 8.1 新特性 - 控件之列表选择控件

    本篇我们来介绍Windows Phone 8.1 新特性中的列表选择控件. 在Windows Phone 8 时代,大家都会使用 LongListSelector 来实现列表选择控件,对数据进行分组显 ...

  3. SNF开发平台WinForm之三-开发-单表选择控件创建-SNF快速开发平台3.3-Spring.Net.Framework

    3.1运行效果: 3.2开发实现: 3.2.1 这个开发与第一个开发操作步骤是一致的,不同之处就是在生成完代码之后,留下如下圈红程序,其它删除. 第一个开发地址:开发-单表表格编辑管理页面 http: ...

  4. 用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(一)

    本文为原创,如有转载,请注明出处:http://www.cnblogs.com/jackybu 前言 章节: 1.需求描述以及c/c++实现日期和月历的基本操作 2.ios实现自绘日期选择控件 3.a ...

  5. js 跨域的问题 (同一个主域名不同的二级域名下的跨域问题) 解决 WdatePicker.js my97日期选择控件

    例如域名是  a.xx.com  和 b.xx.com    如果一个页面中引入多个iframe,要想能够操作所有iframe,必须都得设置相同domain. 如果iframe的时候  a包含b  为 ...

  6. JQuery好用的日期选择控件 DatePicker

    近期发现一个很好的基于JQ的前端UI日期选择控件Jquery.DatePicker.js 下载地址:jquery.DatePIcker.js 演示地址:DatePicker - 基于jQuery 1. ...

  7. [Ext JS 4] 实战之 带week(星期)的日期选择控件(三)

    前言 在 [Ext JS 4] 实战之 带week(星期)的日期选择控件(二) 的最后,有提到一个解决方案. 不过这方案有一个条件  ==> “2. 每年的周数从(1-52), 如果超过52 周 ...

  8. 使用sui实现的选择控件【性别、日期、省市级联】

    使用sui mobile做的选择控件,其中sm.js有修改,增加自定义api,详情请看index.html的注释,不多说了,上代码 <!DOCTYPE html> <html> ...

  9. android中选择控件与选择界面自然过度效果的实现--一种新的交互设计

    转载请标明出处: http://blog.csdn.net/jianghejie123/article/details/40648931 在安卓中经常遇到须要选择一个东西的功能,比方选择日期.选择文件 ...

随机推荐

  1. 【例题 6-5 UVA 12657 】Boxes in a Line

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 双向链表模拟题. 移动的时候,要注意它就在所需要的位置的情况.那种情况不移动. (如果已经在所需位置了,还用链表的插入方式强行移动的 ...

  2. linux 安装完mysql 密码重置

    If you have forgot the MySQL root password, can’t remember or want to break in….. you can reset them ...

  3. windows关闭进程 批处理端口占用

    cmd 关闭进程java taskkill /F /IM java.exe taskkill /f /im java.exe 如何用dat批处理文件关闭某端口对应程序-Windows自动化命令 如何用 ...

  4. 【JAVA编码专题】UNICODE,GBK,UTF-8区别 分类: B1_JAVA 2015-02-10 21:07 153人阅读 评论(0) 收藏

    简单来说,unicode,gbk和大五码就是编码的值,而utf-8,uft-16之类就是这个值的表现形式.而前面那三种编码是一兼容的,同一个汉字,那三个码值是完全不一样的.如"汉"的uncode值与g ...

  5. php框架排名(Laravel一直第一)

    php框架排名(Laravel一直第一) 一.总结 1.Laravel,后面就用这个框架(要用好这个框架,英语得6啊) 2.YII框架和tp框架一样,也是一个国产框架 二.2017世界PHP框架排名T ...

  6. css3-6 表格如何设置样式和定位样式是什么

    css3-6 表格如何设置样式和定位样式是什么 一.总结 一句话总结:css可以解决所有属性设置的样式. 1.表格如何设置样式? css样式可以解决一切问题,没必要在表格上面加属性来设置样式. 7 t ...

  7. android安卓开发基础小笔记,添加按钮事件,打开新窗体,窗体传值,回传

    给一个按钮添加onclick事件 //获取按钮对象 Button Aiyo = (Button)findViewById(R.id.button1); Aiyo.setOnClickListener( ...

  8. C++ 程序延时处理的几种方法

    (—)使用_sleep()函数 例如:_sleep(200);//延时200毫秒 (二)使用delay(int time)函数 (需要自己实现,编译器里面没有) /// @brief      程序延 ...

  9. Ajax基础与Json应用(二)

    九.jQuery 实现Ajax应用 1.使用load()方法异步请求数据 使用load()方法通过Ajax请求加载服务器中的数据,并把返回的数据放置到指定的元素中,它的调用格式为: load(url, ...

  10. Freemarker中的日期转换

    1. 把数字类型表示的日期,转换成datetime类型,字符串输出.${item.time?number_to_datetime},默认的格式是"yyyy-MM-dd hh:mm:ss&qu ...