编辑
2025-10-10
C#
00

目录

控件预览
完整代码
总结

RangeSlider是一个自定义的Windows Forms控件,允许用户通过两个滑块来选择一个数值范围。这种控件在需要设置数值范围的场景中非常实用,比如价格区间筛选、年龄范围选择等。

本文将详细介绍如何实现一个具有以下特性的RangeSlider控件:

  • 支持最小值和最大值设置
  • 可自定义轨道颜色和高度
  • 平滑的动画效果
  • 精确的值计算
  • 美观的UI设计

控件预览

让我们看看这个控件的效果:

image.png

完整代码

C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AppControls { public class RangeSlider : Control { #region 私有字段 private int _minimum = 0; private int _maximum = 100; private int _lowerValue = 0; private int _upperValue = 100; private Rectangle _trackRectangle; private Rectangle _lowerThumbRect; private Rectangle _upperThumbRect; private bool _isDraggingLower; private bool _isDraggingUpper; private const int THUMB_SIZE = 16; private int _trackHeight = 4; private Color _trackColor = Color.LightGray; private Color _selectedTrackColor = Color.RoyalBlue; #endregion #region 属性 [Description("最小可选值")] public int Minimum { get => _minimum; set { if (value >= _maximum) return; _minimum = value; if (_lowerValue < _minimum) LowerValue = _minimum; Invalidate(); } } [Description("最大可选值")] public int Maximum { get => _maximum; set { if (value <= _minimum) return; _maximum = value; if (_upperValue > _maximum) UpperValue = _maximum; Invalidate(); } } [Description("当前选择的最小值")] public int LowerValue { get => _lowerValue; set { if (value < _minimum || value > _upperValue) return; if (_lowerValue != value) { _lowerValue = value; OnValueChanged(EventArgs.Empty); Invalidate(); } } } [Description("当前选择的最大值")] public int UpperValue { get => _upperValue; set { if (value > _maximum || value < _lowerValue) return; if (_upperValue != value) { _upperValue = value; OnValueChanged(EventArgs.Empty); Invalidate(); } } } [Description("轨道高度")] [DefaultValue(4)] public int TrackHeight { get => _trackHeight; set { if (value < 1) return; if (_trackHeight != value) { _trackHeight = value; Invalidate(); } } } [Description("轨道背景颜色")] public Color TrackColor { get => _trackColor; set { if (_trackColor != value) { _trackColor = value; Invalidate(); } } } [Description("选中区域轨道颜色")] public Color SelectedTrackColor { get => _selectedTrackColor; set { if (_selectedTrackColor != value) { _selectedTrackColor = value; Invalidate(); } } } #endregion #region 事件 public event EventHandler ValueChanged; protected virtual void OnValueChanged(EventArgs e) { ValueChanged?.Invoke(this, e); } #endregion #region 构造函数 public RangeSlider() { SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true); MinimumSize = new Size(100, THUMB_SIZE + 4); } #endregion #region 重写方法 protected override void OnPaint(PaintEventArgs e) { var g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; // 计算轨道区域,使用自定义高度 _trackRectangle = new Rectangle( THUMB_SIZE / 2, Height / 2 - _trackHeight / 2, // 居中显示 Width - THUMB_SIZE, _trackHeight); // 绘制背景轨道,使用自定义颜色 using (var trackBrush = new SolidBrush(_trackColor)) { // 使用圆角矩形绘制轨道 using (var path = CreateRoundedRectangle(_trackRectangle, _trackHeight / 2)) { g.FillPath(trackBrush, path); } } // 计算滑块位置 int lowerX = ValueToPoint(_lowerValue); int upperX = ValueToPoint(_upperValue); // 绘制选中区域,使用自定义颜色 using (var selectedBrush = new SolidBrush(_selectedTrackColor)) { var selectedRect = new Rectangle( lowerX, _trackRectangle.Y, upperX - lowerX, _trackRectangle.Height); // 使用圆角矩形绘制选中区域 using (var path = CreateRoundedRectangle(selectedRect, _trackHeight / 2)) { g.FillPath(selectedBrush, path); } } // 计算滑块矩形 _lowerThumbRect = new Rectangle( lowerX - THUMB_SIZE / 2, Height / 2 - THUMB_SIZE / 2, THUMB_SIZE, THUMB_SIZE); _upperThumbRect = new Rectangle( upperX - THUMB_SIZE / 2, Height / 2 - THUMB_SIZE / 2, THUMB_SIZE, THUMB_SIZE); // 绘制滑块 DrawThumb(g, _lowerThumbRect); DrawThumb(g, _upperThumbRect); } // 创建圆角矩形路径 private GraphicsPath CreateRoundedRectangle(Rectangle rect, int radius) { GraphicsPath path = new GraphicsPath(); if (radius > 0) { int diameter = radius * 2; Rectangle arc = new Rectangle(rect.Location, new Size(diameter, diameter)); // 左上角 path.AddArc(arc, 180, 90); // 上边 arc.X = rect.Right - diameter; path.AddArc(arc, 270, 90); // 右边 arc.Y = rect.Bottom - diameter; path.AddArc(arc, 0, 90); // 下边 arc.X = rect.Left; path.AddArc(arc, 90, 90); path.CloseFigure(); } else { path.AddRectangle(rect); } return path; } protected override void OnMouseDown(MouseEventArgs e) { if (_lowerThumbRect.Contains(e.Location)) { _isDraggingLower = true; } else if (_upperThumbRect.Contains(e.Location)) { _isDraggingUpper = true; } base.OnMouseDown(e); } protected override void OnMouseMove(MouseEventArgs e) { if (_isDraggingLower) { LowerValue = PointToValue(e.X); } else if (_isDraggingUpper) { UpperValue = PointToValue(e.X); } base.OnMouseMove(e); } protected override void OnMouseUp(MouseEventArgs e) { _isDraggingLower = false; _isDraggingUpper = false; base.OnMouseUp(e); } #endregion #region 辅助方法 private void DrawThumb(Graphics g, Rectangle rect) { using (var path = new GraphicsPath()) { path.AddEllipse(rect); using (var brush = new SolidBrush(Color.White)) { g.FillPath(brush, path); } using (var pen = new Pen(Color.DarkGray)) { g.DrawPath(pen, path); } } } private int ValueToPoint(int value) { if (_maximum == _minimum) return _trackRectangle.X; return _trackRectangle.X + (int)((value - _minimum) * _trackRectangle.Width / (_maximum - _minimum)); } private int PointToValue(int x) { if (x < _trackRectangle.X) return _minimum; if (x > _trackRectangle.Right) return _maximum; return _minimum + (x - _trackRectangle.X) * (_maximum - _minimum) / _trackRectangle.Width; } #endregion } }

总结

这个自定义的RangeSlider控件实现了一个美观、实用的范围选择功能,可以很方便地集成到Windows Forms应用程序中。通过属性设置,可以灵活地调整控件的外观和行为,满足不同场景的需求。

该控件的实现涉及了GDI+绘图、事件处理、属性设计等多个方面,是一个很好的自定义控件开发示例。希望这个实现能对你的开发工作有所帮助!

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!