using System.ComponentModel;
using System.Drawing;
using System.Text.Json.Nodes;
using Sim.Host;
namespace System.Windows.Forms;
public enum TickStyle { None, TopLeft, BottomRight, Both }
public enum Orientation { Horizontal, Vertical }
/// 滑动条(教材项目 7 模拟空调温度、窗帘开合)
public class TrackBar : Control, ISupportInitialize
{
private int _minimum;
private int _maximum = 10;
private int _value;
private int _tickFrequency = 1;
private TickStyle _tickStyle = TickStyle.BottomRight;
private Orientation _orientation = Orientation.Horizontal;
private bool _initializing;
public TrackBar() => AutoSize = true;
protected override Size DefaultSize => new(104, 45);
public int Minimum
{
get => _minimum;
set => SetRange(value, Math.Max(value, _maximum));
}
public int Maximum
{
get => _maximum;
set => SetRange(Math.Min(value, _minimum), value);
}
public int Value
{
get => _value;
set
{
if (!_initializing && (value < _minimum || value > _maximum))
throw new ArgumentOutOfRangeException(nameof(value), $"“{value}”的值对于“Value”无效。“Value”应介于 'Minimum' 和 'Maximum' 之间。");
if (SetProp(ref _value, value, nameof(Value))) OnValueChanged(EventArgs.Empty);
}
}
public int TickFrequency
{
get => _tickFrequency;
set => SetProp(ref _tickFrequency, value, nameof(TickFrequency));
}
public TickStyle TickStyle
{
get => _tickStyle;
set => SetProp(ref _tickStyle, value, nameof(TickStyle));
}
public Orientation Orientation
{
get => _orientation;
set
{
if (value == _orientation) return;
SetProp(ref _orientation, value, nameof(Orientation));
Size = new Size(Height, Width);
}
}
public int LargeChange { get; set; } = 5;
public int SmallChange { get; set; } = 1;
public event EventHandler? Scroll;
public event EventHandler? ValueChanged;
protected virtual void OnScroll(EventArgs e) => Scroll?.Invoke(this, e);
protected virtual void OnValueChanged(EventArgs e) => ValueChanged?.Invoke(this, e);
public void SetRange(int minValue, int maxValue)
{
SetProp(ref _minimum, minValue, nameof(Minimum));
SetProp(ref _maximum, Math.Max(minValue, maxValue), nameof(Maximum));
if (_value < _minimum) Value = _minimum;
else if (_value > _maximum) Value = _maximum;
}
// Designer.cs 里 VS 生成 ((ISupportInitialize)trackBar1).BeginInit() / EndInit():期间先设 Value 再设范围也不报错
public void BeginInit() => _initializing = true;
public void EndInit()
{
_initializing = false;
if (_value < _minimum || _value > _maximum) Value = Math.Clamp(_value, _minimum, _maximum);
}
/// 用户拖动滑块、点轨道或按方向键:和 WinForms 一样先改 Value(ValueChanged),再触发 Scroll
protected override void OnUserAction(UserAction action)
{
if (action.Action != "scroll" || !int.TryParse(action.Value, out var value))
{
base.OnUserAction(action);
return;
}
Value = Math.Clamp(value, _minimum, _maximum);
OnScroll(EventArgs.Empty);
}
protected override void WriteProps(JsonObject props)
{
base.WriteProps(props);
props["Minimum"] = _minimum;
props["Maximum"] = _maximum;
props["Value"] = _value;
props["TickFrequency"] = _tickFrequency;
props["TickStyle"] = _tickStyle.ToString();
props["Orientation"] = _orientation.ToString();
props["LargeChange"] = LargeChange;
props["SmallChange"] = SmallChange;
}
}