- 虚拟时钟:实训台时钟面板可拨时间、1×/10×/60× 倍速、恢复真实时间;编译时把 DateTime.Now / Today / UtcNow 改写成 SimClock;评分规则加 clock 步骤 - 项目资源(Properties.Resources):平台素材库(自绘开关图片、合成门铃声),"项目资源"对话框勾选, 平台生成 Properties/Resources.Designer.cs;设计器图片框的"图片"属性可选资源;程序目录下的 Resources 指向素材库;未添加资源时给中文提示 - Windows Media Player(AxWMPLib):设置 URL 自动播放、Ctlcontrols.play/stop,浏览器里播放声音, 实训台加广播喇叭;编译时给窗体嵌空资源,OcxState 取到 null 不报错;图片和声音统一按内容缓存(blob) - TrackBar:拖动、点轨道、方向键,先 ValueChanged 再 Scroll;设计器加"滑动条""媒体播放器" - 评分规则加 value、media 检查;示例项目 7 任务 1–3(修正书上开关灯判断写反、漏填串口列表) - 修正:Properties/ 下的资源类不当作窗体;带命名空间的 System.AppDomain.CurrentDomain.BaseDirectory 放行 - 测试:虚拟时钟、TrackBar、项目 7 示例评分、作业起点带资源类 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
144 lines
4.8 KiB
C#
144 lines
4.8 KiB
C#
using System.Drawing;
|
||
using System.Globalization;
|
||
using System.Text.Json.Nodes;
|
||
using Sim.Host;
|
||
|
||
namespace System.Windows.Forms;
|
||
|
||
public enum DateTimePickerFormat { Long = 1, Short = 2, Time = 4, Custom = 8 }
|
||
|
||
/// <summary>日期时间选择器(教材项目 6 任务 3 选查询的起止日期)。Text 按 Format 显示,和中文 Windows 一致(Long:2024年1月16日)</summary>
|
||
public class DateTimePicker : Control
|
||
{
|
||
public static readonly DateTime MinimumDateTime = new(1753, 1, 1);
|
||
public static readonly DateTime MaximumDateTime = new(9998, 12, 31);
|
||
|
||
private DateTime _value = SimClock.Now;
|
||
private DateTimePickerFormat _format = DateTimePickerFormat.Long;
|
||
private string? _customFormat;
|
||
private bool _showUpDown;
|
||
private DateTime _minDate = MinimumDateTime;
|
||
private DateTime _maxDate = MaximumDateTime;
|
||
|
||
protected override Size DefaultSize => new(200, 21);
|
||
|
||
public DateTime Value
|
||
{
|
||
get => _value;
|
||
set
|
||
{
|
||
if (value < _minDate || value > _maxDate)
|
||
throw new ArgumentOutOfRangeException(nameof(value), $"“{value}”的值对于“Value”无效。“Value”应介于“MinDate”和“MaxDate”之间。");
|
||
if (value == _value) return;
|
||
LegacyThreads.CheckPoint();
|
||
_value = value;
|
||
NotifyValue();
|
||
OnValueChanged(EventArgs.Empty);
|
||
}
|
||
}
|
||
|
||
public DateTimePickerFormat Format
|
||
{
|
||
get => _format;
|
||
set
|
||
{
|
||
_format = value;
|
||
NotifyValue();
|
||
NotifyChanged(nameof(Format), value);
|
||
}
|
||
}
|
||
|
||
public string? CustomFormat
|
||
{
|
||
get => _customFormat;
|
||
set
|
||
{
|
||
_customFormat = value;
|
||
NotifyValue();
|
||
}
|
||
}
|
||
|
||
public bool ShowUpDown
|
||
{
|
||
get => _showUpDown;
|
||
set => SetProp(ref _showUpDown, value, nameof(ShowUpDown));
|
||
}
|
||
|
||
public DateTime MinDate
|
||
{
|
||
get => _minDate;
|
||
set => _minDate = value;
|
||
}
|
||
|
||
public DateTime MaxDate
|
||
{
|
||
get => _maxDate;
|
||
set => _maxDate = value;
|
||
}
|
||
|
||
public bool ShowCheckBox { get; set; }
|
||
public bool Checked { get; set; } = true;
|
||
public LeftRightAlignment DropDownAlign { get; set; }
|
||
|
||
/// <summary>显示的文字;赋值时按日期解析</summary>
|
||
public override string Text
|
||
{
|
||
get => Display;
|
||
set
|
||
{
|
||
if (string.IsNullOrEmpty(value)) return;
|
||
Value = DateTime.Parse(value, CultureInfo.CurrentCulture);
|
||
}
|
||
}
|
||
|
||
private string Display => _format switch
|
||
{
|
||
DateTimePickerFormat.Short => _value.ToString("d", CultureInfo.CurrentCulture),
|
||
DateTimePickerFormat.Time => _value.ToString("T", CultureInfo.CurrentCulture),
|
||
DateTimePickerFormat.Custom when !string.IsNullOrEmpty(_customFormat) => _value.ToString(_customFormat, CultureInfo.CurrentCulture),
|
||
_ => _value.ToString("D", CultureInfo.CurrentCulture),
|
||
};
|
||
|
||
public event EventHandler? ValueChanged;
|
||
public event EventHandler? CloseUp;
|
||
public event EventHandler? DropDown;
|
||
|
||
protected virtual void OnValueChanged(EventArgs e) => ValueChanged?.Invoke(this, e);
|
||
|
||
/// <summary>浏览器里选了新的日期或时间(ISO 格式,本地时间):和 WinForms 一样先 ValueChanged,再 CloseUp</summary>
|
||
protected override void OnUserAction(UserAction action)
|
||
{
|
||
switch (action.Action)
|
||
{
|
||
case "dropDown":
|
||
DropDown?.Invoke(this, EventArgs.Empty);
|
||
break;
|
||
case "pick" when DateTime.TryParse(action.Value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var picked):
|
||
var clamped = picked < _minDate ? _minDate : picked > _maxDate ? _maxDate : picked;
|
||
if (clamped != _value) Value = clamped;
|
||
else NotifyValue();
|
||
CloseUp?.Invoke(this, EventArgs.Empty);
|
||
break;
|
||
default:
|
||
base.OnUserAction(action);
|
||
break;
|
||
}
|
||
}
|
||
|
||
private void NotifyValue()
|
||
{
|
||
NotifyChanged("Text", Display);
|
||
NotifyChanged("Value", _value.ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture));
|
||
}
|
||
|
||
protected override void WriteProps(JsonObject props)
|
||
{
|
||
base.WriteProps(props);
|
||
props["Value"] = _value.ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture);
|
||
props["Format"] = _format.ToString();
|
||
props["ShowUpDown"] = _showUpDown;
|
||
props["HasTime"] = _format == DateTimePickerFormat.Time || (_format == DateTimePickerFormat.Custom && (_customFormat ?? "").IndexOfAny(['H', 'h', 'm', 's']) >= 0);
|
||
props["HasDate"] = _format != DateTimePickerFormat.Time && !(_format == DateTimePickerFormat.Custom && (_customFormat ?? "").IndexOfAny(['y', 'M', 'd']) < 0);
|
||
}
|
||
}
|