CadParamPluging/UI/DrawingParamsForm.cs
2025-12-17 10:04:08 +08:00

302 lines
10 KiB
C#

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 DrawingParamsForm : Form
{
private readonly TableLayoutPanel _grid;
private readonly Dictionary<string, Control> _controlsByKey;
private readonly ParamCatalog _catalog;
private readonly TemplateSchemaDefinition _schema;
private readonly ToolTip _toolTip;
public ParamBag Result { get; private set; }
public DrawingParamsForm(ParamCatalog catalog, TemplateSchemaDefinition schema)
{
_catalog = (catalog ?? ParamCatalog.CreateDefault()).Clone();
_catalog.Normalize();
_schema = schema;
Text = "填写参数";
Size = new Size(560, 620);
StartPosition = FormStartPosition.CenterParent;
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
ShowInTaskbar = false;
_controlsByKey = new Dictionary<string, Control>(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
};
_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 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(scrollPanel, 0, 1);
root.Controls.Add(buttons, 0, 2);
Controls.Add(root);
AcceptButton = btnOk;
CancelButton = btnCancel;
}
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()
{
var keys = (_schema?.SelectedParamKeys ?? new List<string>()).ToList();
if (keys.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;
}
foreach (var key in keys)
{
var def = _catalog.FindByKey(key);
if (def == null)
{
continue;
}
AddField(def);
}
}
private void AddField(ParamDefinition def)
{
var rowIdx = _grid.RowCount++;
_grid.RowStyles.Add(new RowStyle(SizeType.AutoSize));
var 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);
ctrl.Width = 260;
if (!string.IsNullOrWhiteSpace(def.Hint))
{
_toolTip.SetToolTip(lbl, def.Hint);
_toolTip.SetToolTip(ctrl, def.Hint);
}
_grid.Controls.Add(lbl, 0, rowIdx);
_grid.Controls.Add(ctrl, 1, rowIdx);
_controlsByKey[def.Key] = ctrl;
}
private Control CreateControl(ParamDefinition def)
{
switch (def.Type)
{
case ParamValueType.Bool:
return new CheckBox { Checked = ParseBool(def.DefaultValue), AutoSize = true };
case ParamValueType.Enum:
return CreateEnumCombo(def);
case ParamValueType.Int:
return CreateNumber(def, isInt: true);
case ParamValueType.Double:
return CreateNumber(def, isInt: false);
default:
return new TextBox { Text = def.DefaultValue ?? string.Empty };
}
}
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)
{
// Allow manual edit to match many "下拉列表...可手动编辑" cases.
var cb = new ComboBox { DropDownStyle = ComboBoxStyle.DropDown };
var arr = (def.EnumOptions ?? new List<string>()).Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()).ToArray();
if (arr.Length > 0)
{
cb.Items.AddRange(arr);
var idx = Array.FindIndex(arr, x => string.Equals(x, def.DefaultValue, StringComparison.OrdinalIgnoreCase));
cb.SelectedIndex = idx >= 0 ? idx : 0;
}
if (!string.IsNullOrWhiteSpace(def.DefaultValue))
{
cb.Text = def.DefaultValue;
}
return cb;
}
private Control CreateNumber(ParamDefinition def, bool isInt)
{
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;
}
if (TryParseDecimal(def.DefaultValue, 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;
}
var def = _catalog.FindByKey(key);
if (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(def.Key, value);
}
Result = bag;
DialogResult = DialogResult.OK;
Close();
}
private static string ReadValue(Control ctrl, ParamDefinition def)
{
switch (def.Type)
{
case ParamValueType.Bool:
return (ctrl as CheckBox)?.Checked == true ? "true" : "false";
case ParamValueType.Enum:
return ((ctrl as ComboBox)?.Text ?? string.Empty).Trim();
case ParamValueType.Int:
case ParamValueType.Double:
if (ctrl is NumericUpDown num)
{
return num.Value.ToString(CultureInfo.InvariantCulture);
}
return string.Empty;
default:
return ((ctrl as TextBox)?.Text ?? string.Empty).Trim();
}
}
}
}