CadParamPluging/UI/DrawingParamsForm.cs

932 lines
32 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using CadParamPluging.Common;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
namespace CadParamPluging.UI
{
public class DrawingParamsForm : Form
{
private readonly TableLayoutPanel _grid;
private readonly Dictionary<string, Control> _controlsByKey;
private readonly Dictionary<string, ParamDefinition> _defsByControlKey;
private readonly ParamCatalog _catalog;
private readonly TemplateSchemaDefinition _schema;
private readonly ToolTip _toolTip;
private readonly TabControl _notePreviewTabs;
private readonly RichTextBox _rtbNoteNumbered;
private readonly RichTextBox _rtbNoteRendered;
private Dictionary<int, NoteTemplateEngine.PlaceholderOccurrence> _occByIndex;
// 最小壁厚T自动计算相关
private bool _canAutoCalcMinWallThickness;
private Control _ctrlMinWallThickness;
private const string KeyOuterDiameter1 = "OuterDiameter1";
private const string KeyOuterDiameter1TolMinus = "OuterDiameter1TolMinus";
private const string KeyInnerDiameter2 = "InnerDiameter2";
private const string KeyInnerDiameter2TolPlus = "InnerDiameter2TolPlus";
private const string KeyMinWallThickness = "MinWallThickness";
public ParamBag Result { get; private set; }
private ParamBag _loadedDefaults; // 新增:外部传入的默认值
public DrawingParamsForm(ParamCatalog catalog, TemplateSchemaDefinition schema, ParamBag loadedDefaults = null)
{
_catalog = (catalog ?? ParamCatalog.CreateDefault()).Clone();
_catalog.Normalize();
_schema = schema;
_loadedDefaults = loadedDefaults; // 存储传入的默认值
Text = "填写参数";
Size = new Size(980, 680);
MinimumSize = new Size(900, 620);
StartPosition = FormStartPosition.CenterParent;
FormBorderStyle = FormBorderStyle.Sizable;
MaximizeBox = true;
MinimizeBox = true;
ShowInTaskbar = false;
_controlsByKey = new Dictionary<string, Control>(StringComparer.OrdinalIgnoreCase);
_defsByControlKey = new Dictionary<string, ParamDefinition>(StringComparer.OrdinalIgnoreCase);
_toolTip = new ToolTip();
var root = new TableLayoutPanel
{
Dock = DockStyle.Fill,
Padding = new Padding(10),
ColumnCount = 1,
RowCount = 3
};
root.RowStyles.Add(new RowStyle(SizeType.AutoSize));
root.RowStyles.Add(new RowStyle(SizeType.Percent, 100f));
root.RowStyles.Add(new RowStyle(SizeType.AutoSize));
var header = new Label
{
AutoSize = true,
ForeColor = Color.DarkBlue,
Text = BuildHeaderText(schema)
};
var scrollPanel = new Panel
{
Dock = DockStyle.Fill,
AutoScroll = true
};
_notePreviewTabs = new TabControl { Dock = DockStyle.Fill };
_rtbNoteNumbered = new RichTextBox { Dock = DockStyle.Fill, ReadOnly = true, HideSelection = false };
_rtbNoteRendered = new RichTextBox { Dock = DockStyle.Fill, ReadOnly = true, HideSelection = false };
var tabNumbered = new TabPage { Text = "附注编号预览" };
tabNumbered.Controls.Add(_rtbNoteNumbered);
var tabRendered = new TabPage { Text = "填充值预览" };
tabRendered.Controls.Add(_rtbNoteRendered);
_notePreviewTabs.TabPages.Add(tabNumbered);
_notePreviewTabs.TabPages.Add(tabRendered);
_grid = new TableLayoutPanel
{
Dock = DockStyle.Top,
AutoSize = true,
ColumnCount = 2,
RowCount = 1,
Padding = new Padding(0)
};
_grid.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
_grid.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f));
BuildFields();
scrollPanel.Controls.Add(_grid);
var split = new SplitContainer
{
Dock = DockStyle.Fill,
Orientation = Orientation.Vertical
};
split.Panel1.Controls.Add(scrollPanel);
split.Panel2.Controls.Add(_notePreviewTabs);
split.SizeChanged += (_, __) => EnsureValidSplitterDistance(split);
var buttons = 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();
buttons.Controls.Add(btnCancel);
buttons.Controls.Add(btnOk);
root.Controls.Add(header, 0, 0);
root.Controls.Add(split, 0, 1);
root.Controls.Add(buttons, 0, 2);
Controls.Add(root);
AcceptButton = btnOk;
CancelButton = btnCancel;
Shown += (_, __) =>
{
split.Panel1MinSize = 360;
split.Panel2MinSize = 280;
EnsureValidSplitterDistance(split);
UpdateNotePreviews();
CheckMinWallThicknessAutoCalc();
};
}
private static void EnsureValidSplitterDistance(SplitContainer split)
{
if (split == null)
{
return;
}
// SplitterDistance must be within [Panel1MinSize, Width - Panel2MinSize - SplitterWidth]
var width = split.Width;
if (width <= 0)
{
return;
}
// If container is too narrow, collapse preview panel to avoid throwing.
var required = split.Panel1MinSize + split.Panel2MinSize + split.SplitterWidth + 8;
if (width < required)
{
split.Panel2Collapsed = true;
return;
}
split.Panel2Collapsed = false;
var min = split.Panel1MinSize;
var max = width - split.Panel2MinSize - split.SplitterWidth;
if (max < min)
{
// Too narrow: keep it at minimum to avoid exception.
max = min;
}
var desired = (int)(width * 0.6);
if (desired < min) desired = min;
if (desired > max) desired = max;
try
{
split.SplitterDistance = desired;
}
catch
{
// ignore
}
}
private static string BuildHeaderText(TemplateSchemaDefinition schema)
{
if (schema == null)
{
return "模板参数未配置。";
}
var name = string.IsNullOrWhiteSpace(schema.DisplayName) ? "(未命名模板)" : schema.DisplayName;
return $"模板: {name} | {schema.ProjectType}/{schema.DrawingType}/{schema.SheetSize}/{schema.Scale}";
}
private void BuildFields()
{
_occByIndex = NoteTemplateEngine.ParseOccurrences(_schema?.NoteTemplateText ?? string.Empty)
.Where(o => o != null)
.GroupBy(o => o.Index)
.Select(g => g.First())
.ToDictionary(o => o.Index, o => o);
var forgingDefs = new List<ParamDefinition>();
var partDefs = new List<ParamDefinition>();
var seenMain = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var partKeySet = new HashSet<string>(
(_schema?.SelectedPartParamKeys ?? new List<string>())
.Where(s => !string.IsNullOrWhiteSpace(s))
.Select(s => s.Trim()),
StringComparer.OrdinalIgnoreCase);
foreach (var key in (_schema?.SelectedParamKeys ?? new List<string>()))
{
if (string.IsNullOrWhiteSpace(key))
{
continue;
}
var def = _catalog.FindByKey(key);
if (def == null)
{
continue;
}
if (string.Equals(def.Group ?? string.Empty, "备注参数", StringComparison.OrdinalIgnoreCase))
{
// 备注参数只在附注里填写
continue;
}
if (!seenMain.Add(def.Key))
{
continue;
}
if (partKeySet.Contains(def.Key))
{
partDefs.Add(def);
}
else
{
forgingDefs.Add(def);
}
}
var noteBindings = (_schema?.NoteBindings ?? new List<NotePlaceholderBinding>())
.Where(b => b != null && b.Index > 0 && !string.IsNullOrWhiteSpace(b.ParamKey))
.OrderBy(b => b.Index)
.ToList();
if (forgingDefs.Count == 0 && partDefs.Count == 0 && noteBindings.Count == 0)
{
var rowIdx = _grid.RowCount++;
_grid.RowStyles.Add(new RowStyle(SizeType.AutoSize));
_grid.Controls.Add(new Label { AutoSize = true, Text = "(该模板未绑定任何参数)" }, 0, rowIdx);
_grid.SetColumnSpan(_grid.Controls[_grid.Controls.Count - 1], 2);
return;
}
if (forgingDefs.Count > 0)
{
AddSectionHeader("锻件尺寸");
foreach (var def in forgingDefs)
{
AddField(def, def.Key, def.Label, null);
}
}
if (partDefs.Count > 0)
{
AddSectionHeader("零件尺寸");
foreach (var def in partDefs)
{
AddField(def, def.Key, def.Label, null);
}
}
if (noteBindings.Count > 0)
{
AddSectionHeader("备注参数(附注)");
foreach (var b in noteBindings)
{
var baseKey = (b.ParamKey ?? string.Empty).Trim();
var def = _catalog.FindByKey(baseKey);
if (def == null)
{
continue;
}
// If same ParamKey is used by multiple placeholders, give each placeholder its own value key.
var valueKey = baseKey;
var dupCount = noteBindings.Count(x => string.Equals((x.ParamKey ?? string.Empty).Trim(), baseKey, StringComparison.OrdinalIgnoreCase));
if (dupCount > 1)
{
valueKey = string.Format("{0}@{1}", baseKey, b.Index);
}
var labelText = string.Format("{0} (占位符: #{1})", def.Label, b.Index);
var tip = BuildOccurrenceTip(b.Index);
AddField(def, valueKey, labelText, tip);
}
}
// 收集所有已绑定的参数 key
var boundKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var key in (_schema?.SelectedParamKeys ?? new List<string>()))
{
if (!string.IsNullOrWhiteSpace(key))
{
boundKeys.Add(key.Trim());
}
}
foreach (var b in noteBindings)
{
var key = (b.ParamKey ?? string.Empty).Trim();
if (key.Length > 0)
{
boundKeys.Add(key);
}
}
// 查找必填但未绑定的参数
var unboundRequiredDefs = (_catalog.Items ?? Enumerable.Empty<ParamDefinition>())
.Where(p => p != null && p.Required && !boundKeys.Contains(p.Key ?? string.Empty))
.OrderBy(p => p.Order)
.ToList();
if (unboundRequiredDefs.Count > 0)
{
AddSectionHeader("其他必填参数");
foreach (var def in unboundRequiredDefs)
{
AddField(def, def.Key, def.Label, null);
}
}
}
private string BuildOccurrenceTip(int placeholderIndex)
{
if (_occByIndex == null)
{
return null;
}
if (!_occByIndex.TryGetValue(placeholderIndex, out var o) || o == null)
{
return null;
}
var line = o.LineText ?? string.Empty;
var col = o.ColumnInLine;
if (col < 0) col = 0;
if (col >= line.Length)
{
return string.Format("第{0}行: 【#{1}】", o.LineNumber, placeholderIndex);
}
const int ctx = 18;
var start = Math.Max(0, col - ctx);
var end = Math.Min(line.Length, col + 1 + ctx);
var prefix = start > 0 ? "…" : string.Empty;
var suffix = end < line.Length ? "…" : string.Empty;
var left = line.Substring(start, col - start);
var right = line.Substring(col + 1, end - (col + 1));
var snippet = prefix + left + string.Format("【#{0}】", placeholderIndex) + right + suffix;
return string.Format("第{0}行: {1}", o.LineNumber, snippet);
}
private void AddSectionHeader(string text)
{
var rowIdx = _grid.RowCount++;
_grid.RowStyles.Add(new RowStyle(SizeType.AutoSize));
var lbl = new Label
{
AutoSize = true,
ForeColor = Color.DarkBlue,
Text = text,
Padding = new Padding(0, 10, 0, 4)
};
_grid.Controls.Add(lbl, 0, rowIdx);
_grid.SetColumnSpan(lbl, 2);
}
private void AddField(ParamDefinition def, string controlKey, string labelText, string extraToolTip)
{
var rowIdx = _grid.RowCount++;
_grid.RowStyles.Add(new RowStyle(SizeType.AutoSize));
if (string.IsNullOrWhiteSpace(labelText))
{
labelText = def.Label;
}
if (def.Required)
{
labelText += " *";
}
var lbl = new Label { AutoSize = true, Text = labelText, TextAlign = ContentAlignment.MiddleLeft, Padding = new Padding(0, 6, 8, 6) };
var ctrl = CreateControl(def, controlKey);
ctrl.Width = 260;
if (!string.IsNullOrWhiteSpace(def.Hint))
{
_toolTip.SetToolTip(lbl, def.Hint);
_toolTip.SetToolTip(ctrl, def.Hint);
}
if (!string.IsNullOrWhiteSpace(extraToolTip))
{
_toolTip.SetToolTip(lbl, extraToolTip);
_toolTip.SetToolTip(ctrl, extraToolTip);
}
Control finalCtrl = ctrl;
if (string.Equals(def.Key, "MarkingContent", StringComparison.OrdinalIgnoreCase))
{
var flow = new FlowLayoutPanel
{
AutoSize = true,
FlowDirection = FlowDirection.LeftToRight,
WrapContents = false,
Margin = new Padding(0)
};
bool isChecked = true;
if (_loadedDefaults != null)
{
var showVal = _loadedDefaults.GetString(controlKey + "_ShowInNote");
if (showVal != null)
{
isChecked = showVal == "1" || showVal.Equals("true", StringComparison.OrdinalIgnoreCase);
}
}
var chk = new CheckBox
{
Text = "显示在附注中",
AutoSize = true,
Checked = isChecked,
Margin = new Padding(10, 3, 0, 0)
};
_controlsByKey[controlKey + "_ShowInNote"] = chk;
chk.CheckedChanged += (_, __) => UpdateNotePreviews();
flow.Controls.Add(ctrl);
flow.Controls.Add(chk);
finalCtrl = flow;
}
_grid.Controls.Add(lbl, 0, rowIdx);
_grid.Controls.Add(finalCtrl, 1, rowIdx);
_controlsByKey[controlKey] = ctrl;
_defsByControlKey[controlKey] = def;
AttachPreviewUpdate(ctrl);
AttachMinWallThicknessUpdate(controlKey, ctrl);
}
private void AttachPreviewUpdate(Control ctrl)
{
if (ctrl == null)
{
return;
}
if (ctrl is TextBox tb)
{
tb.TextChanged += (_, __) => UpdateNotePreviews();
return;
}
if (ctrl is ComboBox cb)
{
cb.SelectedIndexChanged += (_, __) => UpdateNotePreviews();
cb.TextChanged += (_, __) => UpdateNotePreviews();
return;
}
if (ctrl is NumericUpDown num)
{
num.ValueChanged += (_, __) => UpdateNotePreviews();
return;
}
if (ctrl is CheckBox chk)
{
chk.CheckedChanged += (_, __) => UpdateNotePreviews();
}
}
private void AttachMinWallThicknessUpdate(string paramKey, Control ctrl)
{
if (ctrl == null || string.IsNullOrWhiteSpace(paramKey))
{
return;
}
var key = paramKey.Trim();
if (!string.Equals(key, KeyOuterDiameter1, StringComparison.OrdinalIgnoreCase)
&& !string.Equals(key, KeyOuterDiameter1TolMinus, StringComparison.OrdinalIgnoreCase)
&& !string.Equals(key, KeyInnerDiameter2, StringComparison.OrdinalIgnoreCase)
&& !string.Equals(key, KeyInnerDiameter2TolPlus, StringComparison.OrdinalIgnoreCase))
{
return;
}
if (ctrl is NumericUpDown num)
{
num.ValueChanged += (_, __) => UpdateMinWallThickness();
}
else if (ctrl is TextBox tb)
{
tb.TextChanged += (_, __) => UpdateMinWallThickness();
}
}
private void CheckMinWallThicknessAutoCalc()
{
_canAutoCalcMinWallThickness = false;
if (!_controlsByKey.ContainsKey(KeyMinWallThickness))
{
return;
}
_ctrlMinWallThickness = _controlsByKey[KeyMinWallThickness];
var hasOuter = _controlsByKey.ContainsKey(KeyOuterDiameter1);
var hasOuterTol = _controlsByKey.ContainsKey(KeyOuterDiameter1TolMinus);
var hasInner = _controlsByKey.ContainsKey(KeyInnerDiameter2);
var hasInnerTol = _controlsByKey.ContainsKey(KeyInnerDiameter2TolPlus);
if (hasOuter && hasOuterTol && hasInner && hasInnerTol)
{
_canAutoCalcMinWallThickness = true;
UpdateMinWallThickness();
if (_ctrlMinWallThickness != null)
{
_toolTip.SetToolTip(_ctrlMinWallThickness, "自动计算: T=((Φ1+b1)-(Φ2+a2))/2\n(根据外径Φ1、外径下差b1、内径Φ2、内径上差a2)");
}
}
else
{
var missing = new List<string>();
if (!hasOuter) missing.Add("外径Φ1");
if (!hasOuterTol) missing.Add("外径下差b1");
if (!hasInner) missing.Add("内径Φ2");
if (!hasInnerTol) missing.Add("内径上差a2");
if (_ctrlMinWallThickness != null && missing.Count > 0)
{
var msg = string.Format("需人工填写(缺少参数: {0}", string.Join(", ", missing));
_toolTip.SetToolTip(_ctrlMinWallThickness, msg);
}
}
}
private void UpdateMinWallThickness()
{
if (!_canAutoCalcMinWallThickness || _ctrlMinWallThickness == null)
{
return;
}
try
{
var phi1 = GetNumericValue(KeyOuterDiameter1);
var b1 = GetNumericValue(KeyOuterDiameter1TolMinus);
var phi2 = GetNumericValue(KeyInnerDiameter2);
var a2 = GetNumericValue(KeyInnerDiameter2TolPlus);
// 注意b1通常为负数如-0.5a2通常为正数如0.5
// 最小壁厚径向T = ((外径最小) - (内径最大)) / 2
// 外径最小 = Φ1 + b1内径最大 = Φ2 + a2
// T = ((Φ1 + b1) - (Φ2 + a2)) / 2
var t = ((phi1 + b1) - (phi2 + a2)) / 2.0;
if (_ctrlMinWallThickness is NumericUpDown num)
{
var val = (decimal)t;
if (val < num.Minimum) val = num.Minimum;
if (val > num.Maximum) val = num.Maximum;
num.Value = val;
}
}
catch
{
// ignore calculation errors
}
}
private double GetNumericValue(string key)
{
if (!_controlsByKey.TryGetValue(key, out var ctrl) || ctrl == null)
{
return 0;
}
if (ctrl is NumericUpDown num)
{
return (double)num.Value;
}
if (ctrl is TextBox tb)
{
if (double.TryParse(tb.Text, NumberStyles.Float, CultureInfo.InvariantCulture, out var v))
{
return v;
}
if (double.TryParse(tb.Text, NumberStyles.Float, CultureInfo.CurrentCulture, out v))
{
return v;
}
}
return 0;
}
private void UpdateNotePreviews()
{
if (_schema == null)
{
_rtbNoteNumbered.Text = "(模板参数未配置)";
_rtbNoteRendered.Text = string.Empty;
return;
}
var noteTemplate = _schema.NoteTemplateText ?? string.Empty;
if (string.IsNullOrWhiteSpace(noteTemplate))
{
_rtbNoteNumbered.Text = "(未配置附注模板文本:请到【设置→模板参数绑定→附注绑定】粘贴附注模板)";
_rtbNoteRendered.Text = string.Empty;
return;
}
_rtbNoteNumbered.Text = NoteTemplateEngine.BuildNumberedPreviewText(noteTemplate);
var tempBag = CollectBagFromUi();
var effective = NoteTemplateEngine.BuildEffectiveValueKeyBindings(_schema.NoteBindings);
Func<string, string> getValueW = (k) =>
{
var val = tempBag.GetString(k);
if (k != null && k.StartsWith("MarkingContent", StringComparison.OrdinalIgnoreCase))
{
if (tempBag.GetString(k + "_ShowInNote") == "0") return "__SKIP_NOTE__";
}
return val;
};
_rtbNoteNumbered.Text = NoteTemplateEngine.BuildNumberedPreviewText(noteTemplate);
_rtbNoteRendered.Text = NoteTemplateEngine.Render(noteTemplate, effective, getValueW);
}
private ParamBag CollectBagFromUi()
{
var bag = new ParamBag();
foreach (var key in _controlsByKey.Keys.ToList())
{
if (!_controlsByKey.TryGetValue(key, out var ctrl) || ctrl == null)
{
continue;
}
if (key.EndsWith("_ShowInNote", StringComparison.OrdinalIgnoreCase))
{
if (ctrl is CheckBox chk)
{
bag.Set(key, chk.Checked ? "1" : "0");
}
continue;
}
if (!_defsByControlKey.TryGetValue(key, out var def) || def == null)
{
continue;
}
var value = ReadValue(ctrl, def);
bag.Set(key, value);
}
return bag;
}
private Control CreateControl(ParamDefinition def, string valueKey)
{
var initialValue = def.DefaultValue;
// 优先使用传入的默认值 (loadedDefaults)
if (_loadedDefaults != null)
{
var val = _loadedDefaults.GetString(valueKey);
if (val != null) // only if key exists
{
initialValue = val;
if (valueKey.StartsWith("Hardness"))
{
// Logging removed
}
}
else
{
if (valueKey.StartsWith("Hardness"))
{
// Logging removed
}
}
}
// 确保不为 null
if (initialValue == null) initialValue = string.Empty;
switch (def.Type)
{
case ParamValueType.Bool:
return new CheckBox { Checked = ParseBool(initialValue), AutoSize = true };
case ParamValueType.Enum:
return CreateEnumCombo(def, initialValue);
case ParamValueType.Int:
return CreateNumber(def, isInt: true, overrideValue: initialValue);
case ParamValueType.Double:
return CreateNumber(def, isInt: false, overrideValue: initialValue);
default:
return new TextBox { Text = initialValue };
}
}
private static bool ParseBool(string s)
{
if (string.IsNullOrWhiteSpace(s))
{
return false;
}
if (bool.TryParse(s, out var v))
{
return v;
}
return string.Equals(s.Trim(), "1", StringComparison.OrdinalIgnoreCase)
|| string.Equals(s.Trim(), "是", StringComparison.OrdinalIgnoreCase);
}
private ComboBox CreateEnumCombo(ParamDefinition def, string initialValue)
{
// Allow manual edit to match many "下拉列表...可手动编辑" cases.
var cb = new ComboBox { DropDownStyle = ComboBoxStyle.DropDown };
var list = (def.EnumOptions ?? new List<string>())
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(x => x.Trim())
.ToList();
var arr = list.ToArray();
if (arr.Length > 0)
{
cb.Items.AddRange(arr);
var idx = Array.FindIndex(arr, x => string.Equals(x, initialValue, StringComparison.OrdinalIgnoreCase));
if (idx >= 0)
{
cb.SelectedIndex = idx;
}
}
if (!string.IsNullOrWhiteSpace(initialValue))
{
cb.Text = initialValue;
}
// Auto-match functionality: filter items as user types (Contains logic)
cb.TextUpdate += (s, e) =>
{
var text = cb.Text;
var selectionStart = cb.SelectionStart;
var selectionLength = cb.SelectionLength;
// Empty text -> Show all? Or keep filtered?
// Usually empty -> Show all.
var matches = string.IsNullOrEmpty(text)
? arr
: list.Where(x => x.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0).ToArray();
cb.BeginUpdate();
cb.Items.Clear();
if (matches.Length > 0)
{
cb.Items.AddRange(matches);
}
cb.EndUpdate();
// Restoring SelectionStart is critical because updating Items resets it
cb.SelectionStart = selectionStart;
cb.SelectionLength = selectionLength;
if (!cb.DroppedDown)
{
cb.DroppedDown = true;
}
// Keep the mouse cursor visible/normal
Cursor.Current = Cursors.Default;
};
return cb;
}
private Control CreateNumber(ParamDefinition def, bool isInt, string overrideValue)
{
var num = new NumericUpDown
{
DecimalPlaces = isInt ? 0 : 3,
Minimum = -1000000000,
Maximum = 1000000000,
ThousandsSeparator = true
};
if (TryParseDecimal(def.Min, out var min))
{
num.Minimum = min;
}
if (TryParseDecimal(def.Max, out var max))
{
num.Maximum = max;
}
// 使用 overrideValue 或 def.DefaultValue
// 但 CreateNumber 被调用时overrideValue 已经是处理过的“最终初始值”
if (TryParseDecimal(overrideValue, out var dv))
{
if (dv < num.Minimum) dv = num.Minimum;
if (dv > num.Maximum) dv = num.Maximum;
num.Value = dv;
}
return num;
}
private static bool TryParseDecimal(string s, out decimal value)
{
value = 0;
if (string.IsNullOrWhiteSpace(s))
{
return false;
}
if (decimal.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
{
return true;
}
return decimal.TryParse(s, NumberStyles.Float, CultureInfo.CurrentCulture, out value);
}
private void OnOk()
{
var bag = new ParamBag();
foreach (var key in _controlsByKey.Keys.ToList())
{
if (!_controlsByKey.TryGetValue(key, out var ctrl) || ctrl == null)
{
continue;
}
if (key.EndsWith("_ShowInNote", StringComparison.OrdinalIgnoreCase))
{
if (ctrl is CheckBox chk)
{
bag.Set(key, chk.Checked ? "1" : "0");
}
continue;
}
if (!_defsByControlKey.TryGetValue(key, out var def) || def == null)
{
continue;
}
var value = ReadValue(ctrl, def);
if (def.Required && string.IsNullOrWhiteSpace(value))
{
MessageBox.Show(this, $"请填写:{def.Label} ({def.Key})", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
ctrl.Focus();
return;
}
bag.Set(key, value);
if (key.StartsWith("Hardness"))
{
// Logging removed
}
}
Result = bag;
DialogResult = DialogResult.OK;
Close();
}
private static string ReadValue(Control ctrl, ParamDefinition def)
{
if (ctrl is CheckBox chk)
{
return chk.Checked ? "true" : "false";
}
if (ctrl is NumericUpDown num)
{
return num.Value.ToString(CultureInfo.InvariantCulture);
}
if (ctrl is ComboBox cb)
{
// Handles both Enum type and String type rendered as ComboBox
return (cb.Text ?? string.Empty).Trim();
}
if (ctrl is TextBox tb)
{
return (tb.Text ?? string.Empty).Trim();
}
return string.Empty;
}
}
}