65.9K
CodeProject 正在变化。 阅读更多。
Home

通用多滑块

starIconstarIconstarIconstarIconstarIcon

5.00/5 (9投票s)

2017 年 5 月 17 日

CPOL

7分钟阅读

viewsIcon

27294

downloadIcon

411

功能全面的多滑块(范围),可以添加、删除和移动箭头(滑块柄)。

下载 MultiSlider_W10_.zip

(Visual Studio 2017)
注意:仅需进行少量修改即可转换为早期版本。

引言

顾名思义,MultiSlider 是一个 UserControl,能够在一个滑轨控件上显示多个箭头。我保留了大部分标准 Slider 控件的行为和外观,并添加了一些小的增强功能。

  • 用户可以通过双击滑轨来添加新箭头(可选)。
  • 用户可以通过 Alt+右键单击来删除箭头(可选)。
  • 箭头具有 IsMoveable 属性;如果设置为 false,则箭头既不能移动也不能删除(在视觉上用箭头上的彩色装饰圆圈表示)。
  • 箭头具有 IsUser 属性;如果设置为 true,则用于为普通箭头着色的画笔将有所不同。用户箭头和标准箭头在其他方面处理方式相同。
  • 支持 AutoToolTipPlacement

注释

使用 Tab 键或 Modifier+光标键在主窗口控件之间进行 Tab 切换时

  1. 如果选中了一个箭头,可以使用 Shift+光标键在任何相邻的箭头之间进行 Tab 切换。
  2. Tab 键不会在任何相邻的箭头之间切换,只会切换到控件。
  3. 当 Tab 键切换到 MultiSlider 控件时,按下空格键将激活先前选中的箭头。
  4. Control+光标键在 Tab 切换控件时按正常方式工作。

市面上有一些多滑块工具

  1. https://codeproject.org.cn/Articles/626132/WPF-MultiRangeSlider-Control

    此文章发布于 2013 年,使用的是 Windows 7 箭头样式,因此不适用于 W10 风格。功能有限,但可以添加新箭头。

  2. http://avaloncontrolslib.codeplex.com/

    这个更老(2007 年)。

  3. http://www.telerik.com/products/wpf/slider.aspx?utm_source=google&utm_medium=cpc&gclid=CjwKEAjwl9DIBRCG_e3DwsKsizsSJADMmJ11IH1yTbk4LCKPBdn0Q9rsFBB0G-P1IpyNywq5hAi4_BoCpYfw_wcB&gclsrc=aw.ds&dclid=CKqYk9fy59MCFcKg7QodaLcK5g

    看起来是为 W7 设计的。我没有深入研究过这个。

  4. http://wpftoolkit.codeplex.com/wikipage?title=RangeSlider&referringTitle=Home

    这个只固定为 2 个箭头,不够灵活,但对于其功能来说看起来相当不错。

它们都不够全面以满足我的需求,所以我自己开发了一个。

  • 为程序员提供的事件处理功能已全面考虑(见下文规格)。
  • 我没有包含“刻度”图形和功能(可能以后会添加),但支持 AutoToolTip 功能。

用法

解决方案中有两个项目将演示 MultiSlider 的实际应用。第一个项目 TestSimple 仅显示所有箭头类型、覆盖颜色用法和基本功能。第二个项目 TestMultiSlider 更为全面,包含:

  • 供用户以各种方式操作箭头的设施
  • 用于更改多滑块状态的开关
  • 一个垂直和一个水平方向的多滑块
  • TextBlock 中显示用户操作的读出

属性

  • AdornerColor - (get/set) - 用于箭头装饰圆圈的颜色。如果传递 null,则颜色将被重置。
  • AdornerRatio - (get/set) - 设置/获取装饰圆圈直径与向上箭头宽度之比。如果传递 null,则比率将被重置。
  • ArrowAtIndex(int index) - 返回位置“index”(base=0,从最小值端开始)的 ArrowData
  • ArrowCount - (get) - 滑轨中的箭头数量。
  • ArrowType - (get/set) - MultiSlider.ArrowTypes enum。值:LeftRightUpDownRect
  • AutoToolTipPlacement - (get/set) - 自动工具提示相对于箭头的位置。
  • AutoToolTipPrecision - (get/set) - 将箭头的 Value 打印为 N 位小数。
  • AutoToolTipSigFigs - (get/set) - 如果 N > 0,则将箭头的 Value 打印为 N 位有效数字,并且优先级高于 AutoToolTipPrecision
  • CanDelAddArrows - (get/set) - 用户是否可以使用鼠标添加/删除箭头。
  • HelpText - (get) - 一个 string,包含基本的格式化文本,为用户提供说明。适合添加到 MessageBox 中显示。
  • 最低 - (get/set) - 滑轨中箭头的最小值。设置器将删除所有现有箭头,并且不会触发 ArrowDeleted 事件。
  • Maximum - (get/set) - 滑轨中箭头的最大值。设置器将删除所有现有箭头,并且不会触发 ArrowDeleted 事件。
  • Orientation - (get/set) - 指定滑轨的垂直或水平轴。
  • ReverseDirection - (get/set) - Maximum 是否位于滑轨的最大端或最小端(反之亦然 Minimum)。
  • SchemeOverlayColor - (get,set) - 用于滑轨和普通箭头之上的覆盖颜色(建议 alpha=10%)。
  • SmallChange - (get/set) - 使用键盘光标键移动时,添加到当前箭头值或从中减去的小增量 Value。
  • LargeChange - (get/set) - 使用键盘光标键(+Alt 键)移动时,添加到当前箭头值或从中减去的大增量 Value。
  • Value - (get/set) - 滑轨上第一个箭头的 Value。如果滑轨为空,则得到 DoubleNaN;或者在设置时忽略滑轨。这对于不可删除的单箭头滑块很有用。

方法

  • CreateArrow(double value, bool isUser = false, bool isMoveable = true) - 创建并显示一个新箭头。返回一个 ArrowData
    • "value">TrackBarMinimumMaximum 属性之间的值。
    • "isUser">true:使用箭头的 User 状态画笔。
    • "isMoveable">false:箭头既不能移动也不能删除。
  • DeleteArrow(int index, bool fireEvent) - 从滑轨画布中删除索引为“index”的箭头(base=0,从最小值端开始)。如果 'fireEvent' = true,则触发 ArrowDeleted 事件。
  • DeleteAllArrows(bool fireEvent) - 从滑轨画布中删除所有箭头。如果 'fireEvent' = true,则触发 ArrowDeleted 事件。
  • IsValidValue(value) - 参数是否落在多滑块的 Minimum/Maximum 值范围内。
  • ValueAtIndex(int index) - 返回滑轨上有效箭头索引(base=0,从最小值端开始)的值。

对于箭头(由事件处理程序发送的 ArrowData 类型)

  • Index - (get) - Base 0。滑轨上从最小值端开始的第 n 个箭头。
  • IsMoveable - (get/set) - 箭头是否可以移动/删除。可以动态更改,例如在下面的事件处理程序中。
  • IsUser - (get/set) - 仅当设置“普通”箭头画笔时使用的画笔不同。可以动态更改,例如在下面的事件处理程序中。
  • Value - (get/set) - {MinimumMaximum} 之间的值。

事件

  • ArrowCreated
  • ArrowRightClicked - 如果使用 Alt 键删除箭头,则此事件不会触发。
  • ArrowScrolled
  • ArrowDeleted - 如果焦点更改为相邻箭头,ArrowSelected 也会在之后触发。
  • ArrowLeftClicked
  • ArrowSelected - 当箭头获得键盘焦点时触发(例如,被单击或 Tab 键切换到)。所有发送者 arg 都作为 (object)ArrowData 传递。

实现说明

如果 Minimum==Maximum => 行为有点奇怪但可接受。

MultiSlider 属性窗口中有一个条件编译符号 MULTISLIDER;在调试版本不在调试器外部运行时,更改此符号以阻止控制台输出。

MultiSlider 控件的构建

控件首先有一个 Canvas,代表滑轨(作为 Border),其大小设置为用户控件的大小。然后在此处添加一个 trackbar Border 控件。此 Border 的大小相对于 MultiSliderwidthheight 属性设置。然后,将已创建和初始化的复合箭头添加到主 trackbar Canvas

箭头由一个 Canvas 组成,该 Canvas 被添加到主 trackbar;在此 Canvas 中,首先添加一个初始化的 Polygon 来描述箭头,然后添加一个 Ellipse(充当装饰器),最后添加一个 Label(显示 AutoToolTip 文本)。每当需要更改箭头的视觉位置时,都是将 Canvas 相对于主 trackbar Canvas 进行放置;因此,绝不会访问或更改 Polygon 的点。

使用 Shift+光标键进行箭头键盘焦点

在方法 MultiSlider.Arrow_KeyDown() 中实现了使用 Shift+光标键在控件内的箭头之间进行 Tab 切换。

通过在滑轨上按住鼠标左键进行箭头移动

所有这些都在 trackbarMouseLeftButtonDown/Up 处理程序中完成。在 TrackBar_MouseLeftButtonDown() 中。谓词 if(Mouse.LeftButton == MouseButtonState.Released) 不能在循环中使用,因为当鼠标按钮释放时,报告的 Mouse 按钮状态保持不变。唯一有效的方法是以下方法:

  • 部署一个 iVar 标志 _mouseUp
  • TrackBar_MouseLeftButtonDown() 中将 _mouseUp 设置为 false
  • 编写事件处理程序 TrackBar_MouseLeftButtonUp() - 将 _mouseUp 设置为 true

处理连续按住鼠标按钮

编写一个 BackgroundWorker.DoWork 事件处理程序 ProcessHoldingMouseDown(),并设置 args 为 TrackBar_MouseLeftButtonDown() 传递的所需类型;这将进行鼠标按钮状态检测并执行箭头移动操作。

TrackBar_MouseLeftButtonDown() 中,在要执行箭头移动的地方编写以下代码

BackgroundWorker threadBW = new BackgroundWorker();
threadBW.DoWork += (obj, e2) => ProcessHoldingMouseDown(mouseCoords, arrow);
threadBW.RunWorkerAsync();

ProcessHoldingMouseDown() 中,GUI 主线程调用器部署了多次,例如 Dispatcher.Invoke(() => TrackBar.InitBounds(arrow));

示意图连接

MultiSlider 的行为需要对内部事件处理程序进行相当精细的“调优”。自行修改,后果自负!

一个 Shape.Polygon

RenderBounds() 不考虑任何变换(例如,缩放、旋转)在该形状上。仅包含 StrokeThickness 等,因此当箭头的 Polygon 渲染时,它正好适合其包含的 Canvas

© . All rights reserved.