using System; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.Linq; using System.Windows.Forms; using CadParamPluging.Common; namespace CadParamPluging.UI { public class ParamDefinitionForm : Form { private readonly bool _isEdit; private readonly TextBox _txtKey; private readonly TextBox _txtLabel; private readonly ComboBox _cbType; private readonly CheckBox _chkRequired; private readonly TextBox _txtHint; private readonly TextBox _txtDefault; private readonly TextBox _txtMin; private readonly TextBox _txtMax; private readonly TextBox _txtEnumOptions; private readonly TextBox _txtGroup; private readonly NumericUpDown _numOrder; public ParamDefinition Result { get; private set; } public ParamDefinitionForm(string title, ParamDefinition initial, bool isEdit) { _isEdit = isEdit; Text = title; Size = new Size(520, 520); StartPosition = FormStartPosition.CenterParent; FormBorderStyle = FormBorderStyle.FixedDialog; MaximizeBox = false; MinimizeBox = false; ShowInTaskbar = false; var def = (initial ?? new ParamDefinition()).Clone(); def.Normalize(); var layout = new TableLayoutPanel { Dock = DockStyle.Fill, Padding = new Padding(10), ColumnCount = 2, RowCount = 12, AutoSize = true }; layout.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f)); _txtKey = new TextBox { Width = 260, Text = def.Key }; _txtLabel = new TextBox { Width = 260, Text = def.Label }; _cbType = new ComboBox { DropDownStyle = ComboBoxStyle.DropDownList, Width = 260 }; _cbType.Items.AddRange(Enum.GetNames(typeof(ParamValueType))); _cbType.SelectedItem = def.Type.ToString(); _cbType.SelectedIndexChanged += (_, __) => UpdateTypeUi(); _chkRequired = new CheckBox { Text = "必填", Checked = def.Required, AutoSize = true }; _txtHint = new TextBox { Width = 260, Text = def.Hint, Multiline = true, Height = 60, ScrollBars = ScrollBars.Vertical }; _txtDefault = new TextBox { Width = 260, Text = def.DefaultValue }; _txtMin = new TextBox { Width = 260, Text = def.Min }; _txtMax = new TextBox { Width = 260, Text = def.Max }; _txtEnumOptions = new TextBox { Width = 260, Height = 120, Multiline = true, ScrollBars = ScrollBars.Vertical }; _txtEnumOptions.Text = string.Join(Environment.NewLine, def.EnumOptions ?? new List()); _txtGroup = new TextBox { Width = 260, Text = def.Group }; _numOrder = new NumericUpDown { Width = 120, Minimum = -100000, Maximum = 100000, Value = def.Order }; if (_isEdit) { _txtKey.ReadOnly = true; } var row = 0; layout.Controls.Add(new Label { Text = "Key(英文)", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row); layout.Controls.Add(_txtKey, 1, row++); layout.Controls.Add(new Label { Text = "Label(中文)", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row); layout.Controls.Add(_txtLabel, 1, row++); layout.Controls.Add(new Label { Text = "类型", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row); layout.Controls.Add(_cbType, 1, row++); layout.Controls.Add(new Label { Text = "", AutoSize = true }, 0, row); layout.Controls.Add(_chkRequired, 1, row++); layout.Controls.Add(new Label { Text = "提示/填写方式", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row); layout.Controls.Add(_txtHint, 1, row++); layout.Controls.Add(new Label { Text = "默认值", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row); layout.Controls.Add(_txtDefault, 1, row++); layout.Controls.Add(new Label { Text = "最小值(数字)", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row); layout.Controls.Add(_txtMin, 1, row++); layout.Controls.Add(new Label { Text = "最大值(数字)", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row); layout.Controls.Add(_txtMax, 1, row++); layout.Controls.Add(new Label { Text = "枚举选项(每行一项)", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row); layout.Controls.Add(_txtEnumOptions, 1, row++); layout.Controls.Add(new Label { Text = "分组", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row); layout.Controls.Add(_txtGroup, 1, row++); layout.Controls.Add(new Label { Text = "排序", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row); layout.Controls.Add(_numOrder, 1, row++); var btnPanel = new FlowLayoutPanel { Dock = DockStyle.Fill, FlowDirection = FlowDirection.RightToLeft, AutoSize = true }; var btnCancel = new Button { Text = "取消", DialogResult = DialogResult.Cancel }; var btnOk = new Button { Text = "确定" }; btnOk.Click += (_, __) => OnOk(); btnPanel.Controls.Add(btnCancel); btnPanel.Controls.Add(btnOk); layout.Controls.Add(btnPanel, 0, row); layout.SetColumnSpan(btnPanel, 2); Controls.Add(layout); AcceptButton = btnOk; CancelButton = btnCancel; UpdateTypeUi(); } private void UpdateTypeUi() { var type = GetSelectedType(); var showEnum = type == ParamValueType.Enum; _txtEnumOptions.Enabled = showEnum; var showMinMax = type == ParamValueType.Int || type == ParamValueType.Double; _txtMin.Enabled = showMinMax; _txtMax.Enabled = showMinMax; } private ParamValueType GetSelectedType() { var selected = _cbType.SelectedItem as string; if (Enum.TryParse(selected, out ParamValueType t)) { return t; } return ParamValueType.String; } private void OnOk() { var key = (_txtKey.Text ?? string.Empty).Trim(); var label = (_txtLabel.Text ?? string.Empty).Trim(); if (key.Length == 0) { MessageBox.Show(this, "Key 不能为空。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (!IsValidKey(key)) { MessageBox.Show(this, "Key 格式不合法:必须以字母开头,仅允许字母/数字/下划线。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (label.Length == 0) { MessageBox.Show(this, "Label 不能为空。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } var type = GetSelectedType(); var def = new ParamDefinition { Key = key, Label = label, Type = type, Required = _chkRequired.Checked, Hint = (_txtHint.Text ?? string.Empty).Trim(), DefaultValue = (_txtDefault.Text ?? string.Empty).Trim(), Min = (_txtMin.Text ?? string.Empty).Trim(), Max = (_txtMax.Text ?? string.Empty).Trim(), Group = (_txtGroup.Text ?? string.Empty).Trim(), Order = (int)_numOrder.Value, EnumOptions = ParseLines(_txtEnumOptions.Text) }; def.Normalize(); var err = ValidateDefinition(def); if (err != null) { MessageBox.Show(this, err, "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } Result = def; DialogResult = DialogResult.OK; Close(); } private static List ParseLines(string text) { if (string.IsNullOrWhiteSpace(text)) { return new List(); } return text .Replace("\r\n", "\n") .Replace("\r", "\n") .Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => (s ?? string.Empty).Trim()) .Where(s => s.Length > 0) .ToList(); } private static bool IsValidKey(string key) { if (string.IsNullOrWhiteSpace(key)) { return false; } if (!char.IsLetter(key[0])) { return false; } foreach (var ch in key) { if (char.IsLetterOrDigit(ch) || ch == '_') { continue; } return false; } return true; } private static string ValidateDefinition(ParamDefinition def) { if (def == null) { return "参数定义不能为空。"; } if (def.Type == ParamValueType.Enum && (def.EnumOptions == null || def.EnumOptions.Count == 0)) { return "Enum 类型必须提供至少 1 个枚举选项。"; } if ((def.Type == ParamValueType.Int || def.Type == ParamValueType.Double) && (def.Min.Length > 0 || def.Max.Length > 0)) { if (!TryParseDouble(def.Min, out var min, allowEmpty: true)) { return "最小值不是有效数字。"; } if (!TryParseDouble(def.Max, out var max, allowEmpty: true)) { return "最大值不是有效数字。"; } if (def.Min.Length > 0 && def.Max.Length > 0 && min > max) { return "最小值不能大于最大值。"; } } return null; } private static bool TryParseDouble(string text, out double value, bool allowEmpty) { value = 0; if (string.IsNullOrWhiteSpace(text)) { return allowEmpty; } var s = text.Trim(); if (double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) { return true; } return double.TryParse(s, NumberStyles.Float, CultureInfo.CurrentCulture, out value); } } }