配置了全部参数

This commit is contained in:
sladro 2025-12-17 10:04:08 +08:00
parent d4a9f092ff
commit 0a4a003a11
17 changed files with 2681 additions and 54 deletions

View File

@ -60,6 +60,15 @@
<ItemGroup>
<Compile Include="PluginEntry.cs" />
<Compile Include="Common\BusinessException.cs" />
<Compile Include="Common\ParamBag.cs" />
<Compile Include="Common\ParamCatalog.cs" />
<Compile Include="Common\ParamCatalogStore.cs" />
<Compile Include="Common\ParamDefinition.cs" />
<Compile Include="Common\ParamValueType.cs" />
<Compile Include="Common\TemplateKeyBuilder.cs" />
<Compile Include="Common\TemplateSchemaDefinition.cs" />
<Compile Include="Common\TemplateSchemas.cs" />
<Compile Include="Common\TemplateSchemaStore.cs" />
<Compile Include="Common\DropdownOptions.cs" />
<Compile Include="Common\DropdownOptionsStore.cs" />
<Compile Include="Common\Logger.cs" />
@ -79,15 +88,27 @@
<Compile Include="UI\ParamDrawingPanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="UI\DrawingParamsForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UI\LayoutSelectForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UI\ModelSheetSelectForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UI\ParamCatalogForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UI\ParamDefinitionForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UI\SettingsForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UI\TemplateSchemaBindingForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UI\TextInputForm.cs">
<SubType>Form</SubType>
</Compile>

126
Common/ParamBag.cs Normal file
View File

@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace CadParamPluging.Common
{
[Serializable]
public class ParamBag
{
public List<ParamValue> Items { get; set; }
public ParamBag()
{
Items = new List<ParamValue>();
}
public void Set(string key, string value)
{
if (string.IsNullOrWhiteSpace(key))
{
return;
}
if (Items == null)
{
Items = new List<ParamValue>();
}
var existing = Items.FirstOrDefault(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase));
if (existing == null)
{
Items.Add(new ParamValue { Key = key.Trim(), Value = value });
}
else
{
existing.Value = value;
}
}
public string GetString(string key)
{
if (string.IsNullOrWhiteSpace(key) || Items == null)
{
return null;
}
return Items.FirstOrDefault(x => string.Equals(x.Key, key.Trim(), StringComparison.OrdinalIgnoreCase))?.Value;
}
public double GetDouble(string key, double fallback = 0)
{
var s = GetString(key);
if (string.IsNullOrWhiteSpace(s))
{
return fallback;
}
if (double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var v))
{
return v;
}
if (double.TryParse(s, NumberStyles.Float, CultureInfo.CurrentCulture, out v))
{
return v;
}
return fallback;
}
public int GetInt(string key, int fallback = 0)
{
var s = GetString(key);
if (string.IsNullOrWhiteSpace(s))
{
return fallback;
}
if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var v))
{
return v;
}
if (int.TryParse(s, NumberStyles.Integer, CultureInfo.CurrentCulture, out v))
{
return v;
}
return fallback;
}
public bool GetBool(string key, bool fallback = false)
{
var s = GetString(key);
if (string.IsNullOrWhiteSpace(s))
{
return fallback;
}
if (bool.TryParse(s, out var v))
{
return v;
}
if (string.Equals(s, "1", StringComparison.OrdinalIgnoreCase) || string.Equals(s, "是", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (string.Equals(s, "0", StringComparison.OrdinalIgnoreCase) || string.Equals(s, "否", StringComparison.OrdinalIgnoreCase))
{
return false;
}
return fallback;
}
}
[Serializable]
public class ParamValue
{
public string Key { get; set; }
public string Value { get; set; }
}
}

644
Common/ParamCatalog.cs Normal file
View File

@ -0,0 +1,644 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace CadParamPluging.Common
{
[Serializable]
public class ParamCatalog
{
public List<ParamDefinition> Items { get; set; }
public ParamCatalog()
{
Items = new List<ParamDefinition>();
}
public ParamCatalog Clone()
{
return new ParamCatalog
{
Items = (Items ?? new List<ParamDefinition>()).Select(x => x?.Clone()).Where(x => x != null).ToList()
};
}
public void Normalize()
{
if (Items == null)
{
Items = new List<ParamDefinition>();
}
foreach (var it in Items)
{
it?.Normalize();
}
Items = Items
.Where(x => x != null && !string.IsNullOrWhiteSpace(x.Key))
.GroupBy(x => x.Key, StringComparer.OrdinalIgnoreCase)
.Select(g => g.First())
.OrderBy(x => x.Order)
.ThenBy(x => x.Key, StringComparer.OrdinalIgnoreCase)
.ToList();
}
public ParamDefinition FindByKey(string key)
{
if (string.IsNullOrWhiteSpace(key) || Items == null)
{
return null;
}
return Items.FirstOrDefault(x => string.Equals(x.Key, key.Trim(), StringComparison.OrdinalIgnoreCase));
}
public static ParamCatalog CreateDefault()
{
return new ParamCatalog
{
Items = new List<ParamDefinition>
{
// --- Material / classification ---
new ParamDefinition
{
Key = "MaterialGrade",
Label = "材料牌号",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "数据库下拉列表(支持数据扩充),点选映射",
Order = 100,
Group = "材料"
},
new ParamDefinition
{
Key = "FeatureCategory",
Label = "特性分类",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "一般件",
EnumOptions = new List<string> { "一般件", "关键件", "重要件" },
Hint = "下拉列表(一般件/关键件/重要件),点选;关键件/重要件需加方框标注",
Order = 110,
Group = "材料"
},
new ParamDefinition
{
Key = "MaterialTechnicalCondition",
Label = "材料技术条件",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "多选下拉列表(支持数据扩充),选项用\"或\"连接",
Order = 120,
Group = "材料"
},
new ParamDefinition
{
Key = "ForgingTechnicalCondition",
Label = "锻件技术条件",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "多选下拉列表(支持数据扩充),选项用\"或\"连接",
Order = 130,
Group = "材料"
},
// --- Inspection / heat treatment ---
new ParamDefinition
{
Key = "InspectionCategory",
Label = "检验类别",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "Ⅱ",
EnumOptions = new List<string> { "Ⅱ", "Ⅱa", "Ⅱ大", "Ⅲ", "Ⅳ" },
Hint = "单选下拉列表",
Order = 200,
Group = "检验/热处理"
},
new ParamDefinition
{
Key = "ForgingCategory",
Label = "锻件类别",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "Ⅱ",
EnumOptions = new List<string> { "Ⅱ", "Ⅲ", "Ⅳ" },
Hint = "单选下拉列表",
Order = 210,
Group = "检验/热处理"
},
new ParamDefinition
{
Key = "HeatTreatmentState",
Label = "热处理状态",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "预备热处理",
EnumOptions = new List<string> { "预备热处理", "热处理" },
Hint = "单选下拉列表",
Order = 220,
Group = "检验/热处理"
},
new ParamDefinition
{
Key = "HeatTreatmentProcess",
Label = "热处理制度",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "数据库下拉列表(支持数据扩充),点选",
Order = 230,
Group = "检验/热处理"
},
new ParamDefinition
{
Key = "Hardness",
Label = "硬度",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "组合选择:硬度符号+连接符+数值,可空",
Order = 240,
Group = "检验/热处理"
},
new ParamDefinition
{
Key = "UltrasonicRequirement",
Label = "超声波要求",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "手动输入,可空",
Order = 250,
Group = "检验/热处理"
},
// --- Marking / notes ---
new ParamDefinition
{
Key = "MarkingContent",
Label = "标刻内容",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "多选下拉列表:零件尾号/零件号、材料牌号、熔炼炉号、锭节号、热处理炉次号、热处理炉批号、批次号",
Order = 300,
Group = "标注/说明"
},
new ParamDefinition
{
Key = "PartsPerForging",
Label = "一锻件可做零件数",
Type = ParamValueType.Int,
Required = false,
DefaultValue = "1",
Hint = "手动编辑,默认为\"1\"",
Order = 310,
Group = "标注/说明"
},
new ParamDefinition
{
Key = "SurfaceRoughness",
Label = "表面粗糙度",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "空",
EnumOptions = new List<string> { "空", "0.8", "1.6", "3.2" },
Hint = "单选下拉列表,默认为空",
Order = 320,
Group = "标注/说明"
},
new ParamDefinition
{
Key = "DesignRevision",
Label = "设计图版次",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "空",
EnumOptions = new List<string> { "空", "A", "B", "C", "D", "E", "F" },
Hint = "下拉列表A-F可手动编辑支持空选项",
Order = 330,
Group = "标注/说明"
},
new ParamDefinition
{
Key = "SerialInfo",
Label = "联号信息",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "下拉列表模板\"X个A零件和X个B零件或X个C零件\",点选后可编辑",
Order = 340,
Group = "标注/说明"
},
new ParamDefinition
{
Key = "MachiningSpecimenRequirement",
Label = "机加试件需求",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "下拉列表模板\"每批/每*件多投*件\",点选后可编辑",
Order = 350,
Group = "标注/说明"
},
new ParamDefinition
{
Key = "AdditionalNotes",
Label = "辅助说明",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "多选下拉列表传递抗拉强度实测值、机加夹头标注、使用温度300℃以上、每批投产数量限制点选后可编辑",
Order = 360,
Group = "标注/说明"
},
// --- Template key fields (also exist in panel dropdowns) ---
new ParamDefinition
{
Key = "DeliveryStatus",
Label = "交付状态",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "毛料态",
EnumOptions = new List<string> { "毛料态", "车加工态" },
Hint = "单选下拉列表,决定后续模板",
Order = 400,
Group = "模板参数"
},
new ParamDefinition
{
Key = "ProcessMethod",
Label = "工艺方法",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "自由锻",
EnumOptions = new List<string> { "自由锻", "轧制" },
Hint = "单选下拉列表,决定后续模板",
Order = 410,
Group = "模板参数"
},
new ParamDefinition
{
Key = "StructuralFeature",
Label = "结构特征",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "方体",
EnumOptions = new List<string> { "方体", "饼盘", "轴杆", "环形" },
Hint = "单选下拉列表,决定后续模板",
Order = 420,
Group = "模板参数"
},
new ParamDefinition
{
Key = "SpecialCondition",
Label = "特殊条件",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "非中心冲孔",
EnumOptions = new List<string> { "非中心冲孔", "中心冲孔", "无圆头", "有圆头", "圆轴", "方轴" },
Hint = "单选下拉列表,决定后续模板",
Order = 430,
Group = "模板参数"
},
// --- Dimensions: ring (outer/inner/height) ---
new ParamDefinition
{
Key = "OuterDiameter1",
Label = "外径Φ1",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "手动编辑",
Order = 500,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "OuterDiameter1TolPlus",
Label = "外径上差a1",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "0.5",
Hint = "车加工态:手动编辑(默认+0.5);毛料态:下拉列表(+2~+7",
Order = 510,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "OuterDiameter1TolMinus",
Label = "外径下差b1",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "-0.5",
Hint = "车加工态:手动编辑(默认-0.5);毛料态:下拉列表(-2~-7",
Order = 520,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "InnerDiameter2",
Label = "内径Φ2",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "手动编辑",
Order = 530,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "InnerDiameter2TolPlus",
Label = "内径上差a2",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "0.5",
Hint = "车加工态:手动编辑(默认+0.5);毛料态:下拉列表(+2~+7",
Order = 540,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "InnerDiameter2TolMinus",
Label = "内径下差b2",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "-0.5",
Hint = "车加工态:手动编辑(默认-0.5);毛料态:下拉列表(-2~-7",
Order = 550,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "Height1",
Label = "高度H1",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "手动编辑",
Order = 560,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "Height1TolPlus",
Label = "高度上差a3",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "0.5",
Hint = "车加工态:手动编辑(默认+0.5);毛料态:下拉列表(+2~+7",
Order = 570,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "Height1TolMinus",
Label = "高度下差b3",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "-0.5",
Hint = "车加工态:手动编辑(默认-0.5);毛料态:下拉列表(-2~-7",
Order = 580,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "MinWallThickness",
Label = "最小壁厚T",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "自动计算T=(Φ1-b1+Φ2-a2)/2",
Order = 590,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "UnspecifiedFilletRadiusMax",
Label = "未注圆角半径R≤",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "",
EnumOptions = new List<string> { "6", "5", "4" },
Hint = "下拉列表6/5/4可手动编辑",
Order = 600,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "InnerRadiusMax",
Label = "内径半径R≤",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "",
EnumOptions = new List<string> { "8", "10" },
Hint = "仅中心冲孔结构下拉列表8/10可手动编辑",
Order = 610,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "RoundHeadFilletRadiusMax",
Label = "圆头处圆角半径≤",
Type = ParamValueType.Enum,
Required = false,
DefaultValue = "",
EnumOptions = new List<string> { "8", "10" },
Hint = "仅方体有圆头结构下拉列表8/10可手动编辑",
Order = 620,
Group = "尺寸-环形"
},
new ParamDefinition
{
Key = "PartDimensionsPrime",
Label = "零件尺寸(Φ'1/Φ'2/H'1等",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "手动编辑",
Order = 630,
Group = "尺寸-环形"
},
// --- Dimensions: shaft/rod (diameter/length) ---
new ParamDefinition
{
Key = "Diameter",
Label = "直径Φ",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "手动编辑",
Order = 700,
Group = "尺寸-轴杆"
},
new ParamDefinition
{
Key = "DiameterTolPlus",
Label = "直径Φ上差a1",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "下拉列表(+2~+7可手动编辑",
Order = 710,
Group = "尺寸-轴杆"
},
new ParamDefinition
{
Key = "DiameterTolMinus",
Label = "直径Φ下差b1",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "下拉列表(-2~-7可手动编辑",
Order = 720,
Group = "尺寸-轴杆"
},
new ParamDefinition
{
Key = "Length",
Label = "长度L",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "手动编辑",
Order = 730,
Group = "尺寸-轴杆"
},
new ParamDefinition
{
Key = "LengthTolPlus",
Label = "长度L上差a2",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "下拉列表(+2~+7可手动编辑",
Order = 740,
Group = "尺寸-轴杆"
},
new ParamDefinition
{
Key = "LengthTolMinus",
Label = "长度L下差b2",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "下拉列表(-2~-7可手动编辑",
Order = 750,
Group = "尺寸-轴杆"
},
// --- Dimensions: generic multi-size ---
new ParamDefinition
{
Key = "Size123",
Label = "尺寸1/尺寸2/尺寸3",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "手动编辑",
Order = 800,
Group = "尺寸-通用"
},
new ParamDefinition
{
Key = "SizeTolPlusA123",
Label = "尺寸上差a1/a2/a3",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "下拉列表(+2~+7可手动编辑",
Order = 810,
Group = "尺寸-通用"
},
new ParamDefinition
{
Key = "SizeTolMinusB123",
Label = "尺寸下差b1/b2/b3",
Type = ParamValueType.String,
Required = false,
DefaultValue = "",
Hint = "下拉列表(-2~-7可手动编辑",
Order = 820,
Group = "尺寸-通用"
},
// --- Dimensions: disk (饼盘) ---
new ParamDefinition
{
Key = "DiskDiameter",
Label = "直径Φ(饼盘)",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "手动编辑",
Order = 900,
Group = "尺寸-饼盘"
},
new ParamDefinition
{
Key = "DiskDiameterTolPlus",
Label = "直径Φ上差a1饼盘",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "下拉列表(+2~+7可手动编辑",
Order = 910,
Group = "尺寸-饼盘"
},
new ParamDefinition
{
Key = "DiskDiameterTolMinus",
Label = "直径Φ下差b1饼盘",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "下拉列表(-2~-7可手动编辑",
Order = 920,
Group = "尺寸-饼盘"
},
new ParamDefinition
{
Key = "DiskHeight",
Label = "高度H饼盘",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "手动编辑",
Order = 930,
Group = "尺寸-饼盘"
},
new ParamDefinition
{
Key = "DiskHeightTolPlus",
Label = "高度H上差a2饼盘",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "下拉列表(+2~+7可手动编辑",
Order = 940,
Group = "尺寸-饼盘"
},
new ParamDefinition
{
Key = "DiskHeightTolMinus",
Label = "高度H下差b2饼盘",
Type = ParamValueType.Double,
Required = false,
DefaultValue = "",
Hint = "下拉列表(-2~-7可手动编辑",
Order = 950,
Group = "尺寸-饼盘"
}
}
};
}
}
}

118
Common/ParamCatalogStore.cs Normal file
View File

@ -0,0 +1,118 @@
using System;
using System.IO;
using System.Xml.Serialization;
namespace CadParamPluging.Common
{
public static class ParamCatalogStore
{
private const string FolderName = "CadParamPluging";
private const string FileName = "param-catalog.xml";
public static string GetFilePath()
{
var dir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
FolderName);
return Path.Combine(dir, FileName);
}
public static ParamCatalog Load()
{
try
{
var defaults = ParamCatalog.CreateDefault();
defaults.Normalize();
var path = GetFilePath();
if (!File.Exists(path))
{
return defaults;
}
using (var stream = File.OpenRead(path))
{
var serializer = new XmlSerializer(typeof(ParamCatalog));
var obj = serializer.Deserialize(stream) as ParamCatalog;
if (obj == null)
{
return defaults;
}
obj.Normalize();
// Merge: keep local modifications, but add any missing keys from built-in defaults.
foreach (var def in defaults.Items)
{
if (obj.FindByKey(def.Key) == null)
{
obj.Items.Add(def.Clone());
continue;
}
var existing = obj.FindByKey(def.Key);
if (existing != null)
{
if (string.IsNullOrWhiteSpace(existing.Label) && !string.IsNullOrWhiteSpace(def.Label))
{
existing.Label = def.Label;
}
if (string.IsNullOrWhiteSpace(existing.Group) && !string.IsNullOrWhiteSpace(def.Group))
{
existing.Group = def.Group;
}
}
}
// Migration: remove legacy demo parameters if they exist.
obj.Items = (obj.Items ?? new System.Collections.Generic.List<ParamDefinition>())
.Where(x => x != null
&& !string.Equals(x.Key, "Width", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(x.Key, "Height", StringComparison.OrdinalIgnoreCase))
.ToList();
obj.Normalize();
return obj;
}
}
catch
{
var defaults = ParamCatalog.CreateDefault();
defaults.Normalize();
return defaults;
}
}
public static void Save(ParamCatalog catalog)
{
if (catalog == null)
{
throw new ArgumentNullException(nameof(catalog));
}
catalog.Normalize();
var path = GetFilePath();
var dir = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(dir))
{
Directory.CreateDirectory(dir);
}
var tempPath = path + ".tmp";
var serializer = new XmlSerializer(typeof(ParamCatalog));
using (var stream = File.Create(tempPath))
{
serializer.Serialize(stream, catalog);
}
if (File.Exists(path))
{
File.Delete(path);
}
File.Move(tempPath, path);
}
}
}

83
Common/ParamDefinition.cs Normal file
View File

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace CadParamPluging.Common
{
[Serializable]
public class ParamDefinition
{
public string Key { get; set; }
public string Label { get; set; }
public ParamValueType Type { get; set; }
public bool Required { get; set; }
/// <summary>
/// Free-form note, typically the original "填写方式".
/// </summary>
public string Hint { get; set; }
/// <summary>
/// Stored as string for XML friendliness.
/// </summary>
public string DefaultValue { get; set; }
/// <summary>
/// Numeric constraints stored as string for XML friendliness.
/// </summary>
public string Min { get; set; }
public string Max { get; set; }
public List<string> EnumOptions { get; set; }
public string Group { get; set; }
public int Order { get; set; }
public ParamDefinition()
{
EnumOptions = new List<string>();
}
public ParamDefinition Clone()
{
return new ParamDefinition
{
Key = Key,
Label = Label,
Type = Type,
Required = Required,
Hint = Hint,
DefaultValue = DefaultValue,
Min = Min,
Max = Max,
EnumOptions = (EnumOptions ?? new List<string>()).ToList(),
Group = Group,
Order = Order
};
}
public void Normalize()
{
Key = (Key ?? string.Empty).Trim();
Label = (Label ?? string.Empty).Trim();
Hint = (Hint ?? string.Empty).Trim();
DefaultValue = (DefaultValue ?? string.Empty).Trim();
Min = (Min ?? string.Empty).Trim();
Max = (Max ?? string.Empty).Trim();
Group = (Group ?? string.Empty).Trim();
if (EnumOptions != null)
{
EnumOptions = EnumOptions
.Where(s => !string.IsNullOrWhiteSpace(s))
.Select(s => s.Trim())
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
}
else
{
EnumOptions = new List<string>();
}
}
}
}

11
Common/ParamValueType.cs Normal file
View File

@ -0,0 +1,11 @@
namespace CadParamPluging.Common
{
public enum ParamValueType
{
String = 0,
Int = 1,
Double = 2,
Bool = 3,
Enum = 4
}
}

View File

@ -0,0 +1,55 @@
using System;
using System.Linq;
using CadParamPluging.Domain.Models;
namespace CadParamPluging.Common
{
public static class TemplateKeyBuilder
{
public static string Build(TemplateParams tpl)
{
if (tpl == null)
{
return null;
}
return Build(tpl.ProjectType, tpl.DrawingType, tpl.SheetSize, tpl.Scale);
}
public static string Build(string projectType, string drawingType, string sheetSize, string scale)
{
var p1 = NormalizeValue(projectType);
var p2 = NormalizeValue(drawingType);
var p3 = NormalizeValue(sheetSize);
var p4 = NormalizeScale(scale);
return string.Join("|", new[] { p1, p2, p3, p4 });
}
private static string NormalizeScale(string s)
{
if (string.IsNullOrWhiteSpace(s))
{
return string.Empty;
}
if (string.Equals(s.Trim(), "无", StringComparison.OrdinalIgnoreCase))
{
return string.Empty;
}
return NormalizeValue(s);
}
private static string NormalizeValue(string s)
{
if (string.IsNullOrWhiteSpace(s))
{
return string.Empty;
}
var trimmed = s.Trim();
var chars = trimmed.Where(c => !char.IsWhiteSpace(c)).ToArray();
return new string(chars);
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace CadParamPluging.Common
{
[Serializable]
public class TemplateSchemaDefinition
{
public string TemplateKey { get; set; }
public string ProjectType { get; set; }
public string DrawingType { get; set; }
public string SheetSize { get; set; }
public string Scale { get; set; }
public string DisplayName { get; set; }
public List<string> SelectedParamKeys { get; set; }
public TemplateSchemaDefinition()
{
SelectedParamKeys = new List<string>();
}
public void Normalize()
{
ProjectType = (ProjectType ?? string.Empty).Trim();
DrawingType = (DrawingType ?? string.Empty).Trim();
SheetSize = (SheetSize ?? string.Empty).Trim();
Scale = (Scale ?? string.Empty).Trim();
DisplayName = (DisplayName ?? string.Empty).Trim();
TemplateKey = TemplateKeyBuilder.Build(ProjectType, DrawingType, SheetSize, Scale);
if (SelectedParamKeys == null)
{
SelectedParamKeys = new List<string>();
}
SelectedParamKeys = SelectedParamKeys
.Where(s => !string.IsNullOrWhiteSpace(s))
.Select(s => s.Trim())
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
}
}
}

View File

@ -0,0 +1,89 @@
using System;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
namespace CadParamPluging.Common
{
public static class TemplateSchemaStore
{
private const string FolderName = "CadParamPluging";
private const string FileName = "template-schemas.xml";
public static string GetFilePath()
{
var dir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
FolderName);
return Path.Combine(dir, FileName);
}
public static TemplateSchemas Load()
{
try
{
var path = GetFilePath();
if (!File.Exists(path))
{
return new TemplateSchemas();
}
using (var stream = File.OpenRead(path))
{
var serializer = new XmlSerializer(typeof(TemplateSchemas));
var obj = serializer.Deserialize(stream) as TemplateSchemas;
if (obj == null)
{
return new TemplateSchemas();
}
obj.Normalize();
if (obj.Items != null)
{
obj.Items = obj.Items
.Where(x => x != null && !string.IsNullOrWhiteSpace(x.TemplateKey))
.GroupBy(x => x.TemplateKey, StringComparer.OrdinalIgnoreCase)
.Select(g => g.First())
.ToList();
}
return obj;
}
}
catch
{
return new TemplateSchemas();
}
}
public static void Save(TemplateSchemas schemas)
{
if (schemas == null)
{
throw new ArgumentNullException(nameof(schemas));
}
schemas.Normalize();
var path = GetFilePath();
var dir = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(dir))
{
Directory.CreateDirectory(dir);
}
var tempPath = path + ".tmp";
var serializer = new XmlSerializer(typeof(TemplateSchemas));
using (var stream = File.Create(tempPath))
{
serializer.Serialize(stream, schemas);
}
if (File.Exists(path))
{
File.Delete(path);
}
File.Move(tempPath, path);
}
}
}

29
Common/TemplateSchemas.cs Normal file
View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
namespace CadParamPluging.Common
{
[Serializable]
public class TemplateSchemas
{
public List<TemplateSchemaDefinition> Items { get; set; }
public TemplateSchemas()
{
Items = new List<TemplateSchemaDefinition>();
}
public void Normalize()
{
if (Items == null)
{
Items = new List<TemplateSchemaDefinition>();
}
foreach (var it in Items)
{
it?.Normalize();
}
}
}
}

View File

@ -41,10 +41,7 @@ namespace CadParamPluging.Domain
throw new BusinessException("请填写项目类型和图纸类型。");
}
if (drawingParams == null || !drawingParams.HasValidSize())
{
throw new BusinessException("请填写有效的出图尺寸(宽度和高度需大于 0。");
}
// 出图参数由不同模板决定,后续由模板对应的生成器做更精细的校验。
}
public static void DrawByParams(TemplateInfo template, DrawingParams drawingParams, CadDrawingService cadService)

301
UI/DrawingParamsForm.cs Normal file
View File

@ -0,0 +1,301 @@
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();
}
}
}
}

222
UI/ParamCatalogForm.cs Normal file
View File

@ -0,0 +1,222 @@
using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using CadParamPluging.Common;
namespace CadParamPluging.UI
{
public class ParamCatalogForm : Form
{
private readonly ListBox _list;
private ParamCatalog _catalog;
public ParamCatalogForm(ParamCatalog initial)
{
Text = "参数总表";
Size = new Size(640, 520);
StartPosition = FormStartPosition.CenterParent;
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
ShowInTaskbar = false;
_catalog = (initial ?? ParamCatalog.CreateDefault()).Clone();
_catalog.Normalize();
var layout = new TableLayoutPanel
{
Dock = DockStyle.Fill,
Padding = new Padding(10),
ColumnCount = 2,
RowCount = 2
};
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f));
layout.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100f));
layout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
_list = new ListBox { Dock = DockStyle.Fill };
ReloadList();
var actions = new FlowLayoutPanel
{
Dock = DockStyle.Fill,
FlowDirection = FlowDirection.TopDown,
WrapContents = false,
AutoSize = true
};
var btnAdd = new Button { Text = "新增", AutoSize = true };
btnAdd.Click += (_, __) => OnAdd();
var btnEdit = new Button { Text = "修改", AutoSize = true };
btnEdit.Click += (_, __) => OnEdit();
var btnDelete = new Button { Text = "删除", AutoSize = true };
btnDelete.Click += (_, __) => OnDelete();
actions.Controls.Add(btnAdd);
actions.Controls.Add(btnEdit);
actions.Controls.Add(btnDelete);
var btnPanel = new FlowLayoutPanel
{
Dock = DockStyle.Fill,
FlowDirection = FlowDirection.RightToLeft,
AutoSize = true
};
var btnClose = new Button { Text = "关闭", DialogResult = DialogResult.Cancel };
var btnSave = new Button { Text = "保存" };
btnSave.Click += (_, __) => OnSave();
btnPanel.Controls.Add(btnClose);
btnPanel.Controls.Add(btnSave);
layout.Controls.Add(_list, 0, 0);
layout.Controls.Add(actions, 1, 0);
layout.Controls.Add(btnPanel, 0, 1);
layout.SetColumnSpan(btnPanel, 2);
Controls.Add(layout);
CancelButton = btnClose;
}
private void ReloadList()
{
_list.Items.Clear();
foreach (var it in (_catalog.Items ?? Enumerable.Empty<ParamDefinition>()).OrderBy(x => x.Order))
{
_list.Items.Add(Format(it));
}
if (_list.Items.Count > 0)
{
_list.SelectedIndex = 0;
}
}
private static string Format(ParamDefinition def)
{
if (def == null)
{
return "(null)";
}
var label = string.IsNullOrWhiteSpace(def.Label) ? def.Key : def.Label;
return $"{label} ({def.Key}) [{def.Type}]";
}
private ParamDefinition GetSelected()
{
var idx = _list.SelectedIndex;
if (idx < 0 || _catalog.Items == null)
{
return null;
}
var ordered = _catalog.Items.OrderBy(x => x.Order).ThenBy(x => x.Key, StringComparer.OrdinalIgnoreCase).ToList();
if (idx >= ordered.Count)
{
return null;
}
var selKey = ordered[idx].Key;
return _catalog.FindByKey(selKey);
}
private void OnAdd()
{
using (var f = new ParamDefinitionForm("新增参数", new ParamDefinition { Type = ParamValueType.String }, isEdit: false))
{
if (f.ShowDialog(this) != DialogResult.OK)
{
return;
}
var def = f.Result;
if (_catalog.FindByKey(def.Key) != null)
{
MessageBox.Show(this, $"Key 已存在:{def.Key}", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
_catalog.Items.Add(def);
_catalog.Normalize();
ReloadList();
}
}
private void OnEdit()
{
var selected = GetSelected();
if (selected == null)
{
MessageBox.Show(this, "请先选择一项再修改。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
using (var f = new ParamDefinitionForm("修改参数", selected, isEdit: true))
{
if (f.ShowDialog(this) != DialogResult.OK)
{
return;
}
var updated = f.Result;
var existing = _catalog.FindByKey(updated.Key);
if (existing == null)
{
_catalog.Items.Add(updated);
}
else
{
existing.Label = updated.Label;
existing.Type = updated.Type;
existing.Required = updated.Required;
existing.Hint = updated.Hint;
existing.DefaultValue = updated.DefaultValue;
existing.Min = updated.Min;
existing.Max = updated.Max;
existing.EnumOptions = updated.EnumOptions;
existing.Group = updated.Group;
existing.Order = updated.Order;
existing.Normalize();
}
_catalog.Normalize();
ReloadList();
}
}
private void OnDelete()
{
var selected = GetSelected();
if (selected == null)
{
MessageBox.Show(this, "请先选择一项再删除。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var confirm = MessageBox.Show(this, $"确认删除参数:{selected.Label} ({selected.Key})", "删除", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (confirm != DialogResult.Yes)
{
return;
}
_catalog.Items = (_catalog.Items ?? Enumerable.Empty<ParamDefinition>())
.Where(x => !string.Equals(x.Key, selected.Key, StringComparison.OrdinalIgnoreCase))
.ToList();
_catalog.Normalize();
ReloadList();
}
private void OnSave()
{
try
{
ParamCatalogStore.Save(_catalog);
MessageBox.Show(this, "已保存。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show(this, $"保存失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}

297
UI/ParamDefinitionForm.cs Normal file
View File

@ -0,0 +1,297 @@
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<string>());
_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<string> ParseLines(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return new List<string>();
}
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);
}
}
}

View File

@ -20,8 +20,6 @@ namespace CadParamPluging.UI
private readonly ComboBox _cbDrawingType;
private readonly ComboBox _cbSheetSize;
private readonly ComboBox _cbScale;
private readonly TextBox _txtWidth;
private readonly TextBox _txtHeight;
private Label _lblTemplateInfo;
private TextBox _txtLog;
private TextBox _txtTemplatePath;
@ -53,8 +51,6 @@ namespace CadParamPluging.UI
_cbDrawingType = CreateComboBox(dropdownOptions.ProcessMethods);
_cbSheetSize = CreateComboBox(dropdownOptions.StructuralFeatures);
_cbScale = CreateComboBox(dropdownOptions.SpecialConditions);
_txtWidth = CreateTextBox("5000");
_txtHeight = CreateTextBox("3000");
var templateGroup = BuildTemplateGroup();
var drawingGroup = BuildDrawingGroup();
@ -135,21 +131,14 @@ namespace CadParamPluging.UI
AutoSizeMode = AutoSizeMode.GrowAndShrink
};
var grid = new TableLayoutPanel
var label = new Label
{
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 3,
AutoSize = true
AutoSize = true,
Padding = new Padding(8),
Text = "出图参数较多,请点击【生成图纸】后在弹窗中填写。"
};
grid.Controls.Add(new Label { Text = "宽度(mm)", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 0);
grid.Controls.Add(_txtWidth, 1, 0);
grid.Controls.Add(new Label { Text = "高度(mm)", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 1);
grid.Controls.Add(_txtHeight, 1, 1);
group.Controls.Add(grid);
group.Controls.Add(label);
return group;
}
@ -524,7 +513,6 @@ namespace CadParamPluging.UI
try
{
var tplParams = CollectTemplateParams();
var drawingParams = CollectDrawingParams();
if (_selectedTemplate == null || string.IsNullOrWhiteSpace(_selectedTemplate.FilePath))
{
@ -542,6 +530,39 @@ namespace CadParamPluging.UI
}
}
var templateKey = TemplateKeyBuilder.Build(tplParams);
if (string.IsNullOrWhiteSpace(templateKey))
{
AppendLog("模板参数不完整,无法生成 TemplateKey。");
return;
}
var schemas = TemplateSchemaStore.Load();
var schema = (schemas?.Items ?? Enumerable.Empty<TemplateSchemaDefinition>())
.FirstOrDefault(s => string.Equals(s.TemplateKey, templateKey, StringComparison.OrdinalIgnoreCase));
if (schema == null)
{
AppendLog($"未找到该模板的参数绑定配置TemplateKey={templateKey})。请到【设置→模板参数绑定】中新增/配置。");
return;
}
var catalog = ParamCatalogStore.Load();
CadParamPluging.Common.ParamBag bag;
using (var f = new DrawingParamsForm(catalog, schema))
{
var r = f.ShowDialog(this);
if (r != DialogResult.OK)
{
AppendLog("用户取消填写参数。");
return;
}
bag = f.Result;
}
// Current demo generator uses a rectangle. Size defaults are handled inside DomainFacade.DrawByParams.
// Real templates will use their own generator/parameters.
var drawingParams = new DrawingParams();
DomainFacade.ValidateParameters(tplParams, drawingParams);
var doc = TemplateDrawingService.CreateDocumentFromTemplate(_selectedTemplate);
@ -669,15 +690,6 @@ namespace CadParamPluging.UI
};
}
private DrawingParams CollectDrawingParams()
{
return new DrawingParams
{
Width = ParseDouble(_txtWidth.Text),
Height = ParseDouble(_txtHeight.Text)
};
}
private static ComboBox CreateComboBox(System.Collections.Generic.IEnumerable<string> items)
{
var cb = new ComboBox
@ -725,25 +737,6 @@ namespace CadParamPluging.UI
}
}
private static TextBox CreateTextBox(string defaultText)
{
return new TextBox { Width = 160, Text = defaultText };
}
private static double ParseDouble(string text)
{
if (double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var value))
{
return value;
}
if (double.TryParse(text, NumberStyles.Float, CultureInfo.CurrentCulture, out value))
{
return value;
}
return 0;
}
private void AppendLog(string message)
{

View File

@ -57,8 +57,32 @@ namespace CadParamPluging.UI
tabs.TabPages.Add(BuildEditableTab("结构特征", _lbStructuralFeatures));
tabs.TabPages.Add(BuildEditableTab("特殊条件", _lbSpecialConditions));
// Bottom buttons
var flowButtons = new FlowLayoutPanel
// Bottom area
var bottom = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 1
};
bottom.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f));
bottom.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
var flowLeft = new FlowLayoutPanel
{
Dock = DockStyle.Fill,
FlowDirection = FlowDirection.LeftToRight,
AutoSize = true
};
var btnParamCatalog = new Button { Text = "参数总表...", AutoSize = true };
btnParamCatalog.Click += (_, __) => OnOpenParamCatalog();
var btnTemplateBinding = new Button { Text = "模板参数绑定...", AutoSize = true };
btnTemplateBinding.Click += (_, __) => OnOpenTemplateBinding();
flowLeft.Controls.Add(btnParamCatalog);
flowLeft.Controls.Add(btnTemplateBinding);
var flowRight = new FlowLayoutPanel
{
Dock = DockStyle.Fill,
FlowDirection = FlowDirection.RightToLeft,
@ -69,11 +93,14 @@ namespace CadParamPluging.UI
var btnOk = new Button { Text = "确定" };
btnOk.Click += (_, __) => OnOk();
flowButtons.Controls.Add(btnCancel);
flowButtons.Controls.Add(btnOk);
flowRight.Controls.Add(btnCancel);
flowRight.Controls.Add(btnOk);
bottom.Controls.Add(flowLeft, 0, 0);
bottom.Controls.Add(flowRight, 1, 0);
layout.Controls.Add(tabs, 0, 0);
layout.Controls.Add(flowButtons, 0, 1);
layout.Controls.Add(bottom, 0, 1);
Controls.Add(layout);
@ -81,6 +108,44 @@ namespace CadParamPluging.UI
CancelButton = btnCancel;
}
private void OnOpenParamCatalog()
{
try
{
var catalog = ParamCatalogStore.Load();
using (var f = new ParamCatalogForm(catalog))
{
f.ShowDialog(this);
}
}
catch (Exception ex)
{
MessageBox.Show(this, $"打开参数总表失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void OnOpenTemplateBinding()
{
try
{
var catalog = ParamCatalogStore.Load();
var projectTypes = _lbDeliveryStatuses.Items.Cast<object>().Select(o => (o as string) ?? string.Empty).ToList();
var drawingTypes = _lbProcessMethods.Items.Cast<object>().Select(o => (o as string) ?? string.Empty).ToList();
var sheetSizes = _lbStructuralFeatures.Items.Cast<object>().Select(o => (o as string) ?? string.Empty).ToList();
var scales = _lbSpecialConditions.Items.Cast<object>().Select(o => (o as string) ?? string.Empty).ToList();
using (var f = new TemplateSchemaBindingForm(projectTypes, drawingTypes, sheetSizes, scales, catalog))
{
f.ShowDialog(this);
}
}
catch (Exception ex)
{
MessageBox.Show(this, $"打开模板参数绑定失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private static void FillList(ListBox listBox, System.Collections.Generic.IEnumerable<string> items)
{
listBox.Items.Clear();

View File

@ -0,0 +1,528 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using CadParamPluging.Common;
namespace CadParamPluging.UI
{
public class TemplateSchemaBindingForm : Form
{
private readonly ComboBox _cbProjectType;
private readonly ComboBox _cbDrawingType;
private readonly ComboBox _cbSheetSize;
private readonly ComboBox _cbScale;
private readonly TextBox _txtDisplayName;
private readonly Label _lblTemplateKey;
private readonly ListBox _lbSchemas;
private readonly ListView _lvParams;
private readonly ParamCatalog _catalog;
private TemplateSchemas _schemas;
public TemplateSchemaBindingForm(
System.Collections.Generic.IEnumerable<string> projectTypes,
System.Collections.Generic.IEnumerable<string> drawingTypes,
System.Collections.Generic.IEnumerable<string> sheetSizes,
System.Collections.Generic.IEnumerable<string> scales,
ParamCatalog catalog)
{
Text = "模板参数绑定";
Size = new Size(920, 620);
StartPosition = FormStartPosition.CenterParent;
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
ShowInTaskbar = false;
_catalog = (catalog ?? ParamCatalog.CreateDefault()).Clone();
_catalog.Normalize();
_schemas = TemplateSchemaStore.Load();
_schemas.Normalize();
var root = new TableLayoutPanel
{
Dock = DockStyle.Fill,
Padding = new Padding(10),
ColumnCount = 2,
RowCount = 2
};
root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 260));
root.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f));
root.RowStyles.Add(new RowStyle(SizeType.Percent, 100f));
root.RowStyles.Add(new RowStyle(SizeType.AutoSize));
_lbSchemas = new ListBox { Dock = DockStyle.Fill };
_lbSchemas.SelectedIndexChanged += (_, __) => LoadSelectedSchemaToUi();
ReloadSchemaList();
var leftButtons = new FlowLayoutPanel
{
Dock = DockStyle.Bottom,
FlowDirection = FlowDirection.LeftToRight,
AutoSize = true
};
var btnNew = new Button { Text = "新增模板", AutoSize = true };
btnNew.Click += (_, __) => OnNewSchema();
var btnDelete = new Button { Text = "删除模板", AutoSize = true };
btnDelete.Click += (_, __) => OnDeleteSchema();
leftButtons.Controls.Add(btnNew);
leftButtons.Controls.Add(btnDelete);
var leftPanel = new Panel { Dock = DockStyle.Fill };
leftPanel.Controls.Add(_lbSchemas);
leftPanel.Controls.Add(leftButtons);
leftButtons.Dock = DockStyle.Bottom;
var editor = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 4,
AutoSize = true
};
editor.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
editor.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f));
_cbProjectType = CreateCombo(projectTypes);
_cbDrawingType = CreateCombo(drawingTypes);
_cbSheetSize = CreateCombo(sheetSizes);
_cbScale = CreateCombo(scales);
_cbProjectType.SelectedIndexChanged += (_, __) => UpdateTemplateKeyLabel();
_cbDrawingType.SelectedIndexChanged += (_, __) => UpdateTemplateKeyLabel();
_cbSheetSize.SelectedIndexChanged += (_, __) => UpdateTemplateKeyLabel();
_cbScale.SelectedIndexChanged += (_, __) => UpdateTemplateKeyLabel();
_txtDisplayName = new TextBox { Width = 380 };
_lblTemplateKey = new Label { AutoSize = true, ForeColor = Color.DarkBlue };
var row = 0;
editor.Controls.Add(new Label { Text = "交付状态", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row);
editor.Controls.Add(_cbProjectType, 1, row++);
editor.Controls.Add(new Label { Text = "工艺方法", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row);
editor.Controls.Add(_cbDrawingType, 1, row++);
editor.Controls.Add(new Label { Text = "结构特征", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row);
editor.Controls.Add(_cbSheetSize, 1, row++);
editor.Controls.Add(new Label { Text = "特殊条件", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row);
editor.Controls.Add(_cbScale, 1, row++);
var topBar = new TableLayoutPanel
{
Dock = DockStyle.Top,
ColumnCount = 2,
RowCount = 2,
AutoSize = true
};
topBar.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
topBar.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f));
topBar.Controls.Add(new Label { Text = "显示名称", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 0);
topBar.Controls.Add(_txtDisplayName, 1, 0);
topBar.Controls.Add(new Label { Text = "TemplateKey", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 1);
topBar.Controls.Add(_lblTemplateKey, 1, 1);
_lvParams = new ListView
{
Dock = DockStyle.Fill,
View = View.Details,
FullRowSelect = true,
HideSelection = false,
CheckBoxes = true
};
_lvParams.Columns.Add("Label", 220);
_lvParams.Columns.Add("Key", 160);
var paramsButtonPanel = new FlowLayoutPanel
{
Dock = DockStyle.Top,
FlowDirection = FlowDirection.LeftToRight,
AutoSize = true
};
var btnUp = new Button { Text = "上移", AutoSize = true };
btnUp.Click += (_, __) => MoveSelectedParam(-1);
var btnDown = new Button { Text = "下移", AutoSize = true };
btnDown.Click += (_, __) => MoveSelectedParam(1);
var btnSelectAll = new Button { Text = "全选", AutoSize = true };
btnSelectAll.Click += (_, __) => SetAllChecked(true);
var btnUnselectAll = new Button { Text = "全不选", AutoSize = true };
btnUnselectAll.Click += (_, __) => SetAllChecked(false);
paramsButtonPanel.Controls.Add(btnUp);
paramsButtonPanel.Controls.Add(btnDown);
paramsButtonPanel.Controls.Add(btnSelectAll);
paramsButtonPanel.Controls.Add(btnUnselectAll);
var rightPanel = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 1,
RowCount = 3
};
rightPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
rightPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
rightPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100f));
rightPanel.Controls.Add(editor, 0, 0);
rightPanel.Controls.Add(topBar, 0, 1);
var paramArea = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 1,
RowCount = 2
};
paramArea.RowStyles.Add(new RowStyle(SizeType.AutoSize));
paramArea.RowStyles.Add(new RowStyle(SizeType.Percent, 100f));
paramArea.Controls.Add(paramsButtonPanel, 0, 0);
paramArea.Controls.Add(_lvParams, 0, 1);
rightPanel.Controls.Add(paramArea, 0, 2);
var bottomButtons = new FlowLayoutPanel
{
Dock = DockStyle.Fill,
FlowDirection = FlowDirection.RightToLeft,
AutoSize = true
};
var btnClose = new Button { Text = "关闭", DialogResult = DialogResult.Cancel };
var btnSave = new Button { Text = "保存" };
btnSave.Click += (_, __) => OnSave();
bottomButtons.Controls.Add(btnClose);
bottomButtons.Controls.Add(btnSave);
root.Controls.Add(leftPanel, 0, 0);
root.Controls.Add(rightPanel, 1, 0);
root.Controls.Add(bottomButtons, 0, 1);
root.SetColumnSpan(bottomButtons, 2);
Controls.Add(root);
CancelButton = btnClose;
BuildParamListItems();
UpdateTemplateKeyLabel();
if (_lbSchemas.Items.Count > 0)
{
_lbSchemas.SelectedIndex = 0;
}
}
private static ComboBox CreateCombo(System.Collections.Generic.IEnumerable<string> items)
{
var cb = new ComboBox { DropDownStyle = ComboBoxStyle.DropDownList, Width = 220 };
var arr = (items ?? Enumerable.Empty<string>())
.Where(s => !string.IsNullOrWhiteSpace(s))
.Select(s => s.Trim())
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
if (arr.Length > 0)
{
cb.Items.AddRange(arr);
cb.SelectedIndex = 0;
}
return cb;
}
private void BuildParamListItems()
{
_lvParams.BeginUpdate();
try
{
_lvParams.Items.Clear();
foreach (var p in (_catalog.Items ?? Enumerable.Empty<ParamDefinition>()).OrderBy(x => x.Order))
{
var it = new ListViewItem(new[] { p.Label, p.Key })
{
Tag = p.Key,
Checked = false
};
_lvParams.Items.Add(it);
}
}
finally
{
_lvParams.EndUpdate();
}
}
private void ApplySchemaToParamList(TemplateSchemaDefinition schema)
{
var selectedKeys = (schema?.SelectedParamKeys ?? new List<string>()).ToList();
var keySet = new HashSet<string>(selectedKeys, StringComparer.OrdinalIgnoreCase);
var all = _lvParams.Items.Cast<ListViewItem>().ToList();
var byKey = all.ToDictionary(i => (string)i.Tag, i => i, StringComparer.OrdinalIgnoreCase);
var ordered = new List<ListViewItem>();
foreach (var k in selectedKeys)
{
if (byKey.TryGetValue(k, out var it))
{
ordered.Add(it);
}
}
foreach (var it in all)
{
if (!keySet.Contains((string)it.Tag))
{
ordered.Add(it);
}
}
_lvParams.BeginUpdate();
try
{
_lvParams.Items.Clear();
foreach (var it in ordered)
{
var key = (string)it.Tag;
it.Checked = keySet.Contains(key);
_lvParams.Items.Add(it);
}
}
finally
{
_lvParams.EndUpdate();
}
}
private void ReloadSchemaList()
{
var prev = _lbSchemas.SelectedIndex;
_lbSchemas.Items.Clear();
foreach (var s in (_schemas.Items ?? Enumerable.Empty<TemplateSchemaDefinition>())
.OrderBy(x => x.ProjectType)
.ThenBy(x => x.DrawingType)
.ThenBy(x => x.SheetSize)
.ThenBy(x => x.Scale))
{
_lbSchemas.Items.Add(FormatSchema(s));
}
if (_lbSchemas.Items.Count > 0)
{
_lbSchemas.SelectedIndex = Math.Max(0, Math.Min(prev, _lbSchemas.Items.Count - 1));
}
}
private static string FormatSchema(TemplateSchemaDefinition s)
{
if (s == null)
{
return "(null)";
}
var name = string.IsNullOrWhiteSpace(s.DisplayName) ? "(未命名)" : s.DisplayName;
return $"{name} | {s.ProjectType}/{s.DrawingType}/{s.SheetSize}/{s.Scale}";
}
private TemplateSchemaDefinition GetSelectedSchema()
{
var idx = _lbSchemas.SelectedIndex;
if (idx < 0)
{
return null;
}
var ordered = (_schemas.Items ?? Enumerable.Empty<TemplateSchemaDefinition>())
.OrderBy(x => x.ProjectType)
.ThenBy(x => x.DrawingType)
.ThenBy(x => x.SheetSize)
.ThenBy(x => x.Scale)
.ToList();
if (idx >= ordered.Count)
{
return null;
}
var key = ordered[idx].TemplateKey;
return (_schemas.Items ?? new List<TemplateSchemaDefinition>()).FirstOrDefault(x => string.Equals(x.TemplateKey, key, StringComparison.OrdinalIgnoreCase));
}
private void LoadSelectedSchemaToUi()
{
var schema = GetSelectedSchema();
if (schema == null)
{
return;
}
SelectComboByText(_cbProjectType, schema.ProjectType);
SelectComboByText(_cbDrawingType, schema.DrawingType);
SelectComboByText(_cbSheetSize, schema.SheetSize);
SelectComboByText(_cbScale, schema.Scale);
_txtDisplayName.Text = schema.DisplayName ?? string.Empty;
UpdateTemplateKeyLabel();
ApplySchemaToParamList(schema);
}
private static void SelectComboByText(ComboBox cb, string value)
{
if (cb == null)
{
return;
}
var v = (value ?? string.Empty).Trim();
for (var i = 0; i < cb.Items.Count; i++)
{
if (string.Equals((cb.Items[i] as string) ?? string.Empty, v, StringComparison.OrdinalIgnoreCase))
{
cb.SelectedIndex = i;
return;
}
}
}
private void UpdateTemplateKeyLabel()
{
var key = TemplateKeyBuilder.Build(_cbProjectType.Text, _cbDrawingType.Text, _cbSheetSize.Text, _cbScale.Text);
_lblTemplateKey.Text = key ?? string.Empty;
}
private void OnNewSchema()
{
if (string.IsNullOrWhiteSpace(_cbProjectType.Text) || string.IsNullOrWhiteSpace(_cbDrawingType.Text))
{
MessageBox.Show(this, "请先选择模板四个参数。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
var candidate = new TemplateSchemaDefinition
{
ProjectType = _cbProjectType.Text,
DrawingType = _cbDrawingType.Text,
SheetSize = _cbSheetSize.Text,
Scale = _cbScale.Text,
DisplayName = _txtDisplayName.Text
};
candidate.Normalize();
if ((_schemas.Items ?? new List<TemplateSchemaDefinition>()).Any(x => string.Equals(x.TemplateKey, candidate.TemplateKey, StringComparison.OrdinalIgnoreCase)))
{
MessageBox.Show(this, "该模板定义已存在(四参数组合重复)。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (_schemas.Items == null)
{
_schemas.Items = new List<TemplateSchemaDefinition>();
}
_schemas.Items.Add(candidate);
_schemas.Normalize();
ReloadSchemaList();
}
private void OnDeleteSchema()
{
var schema = GetSelectedSchema();
if (schema == null)
{
MessageBox.Show(this, "请先选择一个模板定义。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var confirm = MessageBox.Show(this, $"确认删除模板定义:{FormatSchema(schema)}", "删除", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (confirm != DialogResult.Yes)
{
return;
}
_schemas.Items = (_schemas.Items ?? Enumerable.Empty<TemplateSchemaDefinition>())
.Where(x => !string.Equals(x.TemplateKey, schema.TemplateKey, StringComparison.OrdinalIgnoreCase))
.ToList();
_schemas.Normalize();
ReloadSchemaList();
}
private void MoveSelectedParam(int delta)
{
if (_lvParams.SelectedItems.Count == 0)
{
return;
}
var item = _lvParams.SelectedItems[0];
var idx = item.Index;
var newIdx = idx + delta;
if (newIdx < 0 || newIdx >= _lvParams.Items.Count)
{
return;
}
_lvParams.BeginUpdate();
try
{
_lvParams.Items.RemoveAt(idx);
_lvParams.Items.Insert(newIdx, item);
item.Selected = true;
item.Focused = true;
}
finally
{
_lvParams.EndUpdate();
}
}
private void SetAllChecked(bool value)
{
_lvParams.BeginUpdate();
try
{
foreach (ListViewItem it in _lvParams.Items)
{
it.Checked = value;
}
}
finally
{
_lvParams.EndUpdate();
}
}
private void OnSave()
{
var schema = GetSelectedSchema();
if (schema == null)
{
MessageBox.Show(this, "请先选择一个模板定义。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
schema.ProjectType = _cbProjectType.Text;
schema.DrawingType = _cbDrawingType.Text;
schema.SheetSize = _cbSheetSize.Text;
schema.Scale = _cbScale.Text;
schema.DisplayName = _txtDisplayName.Text;
schema.SelectedParamKeys = _lvParams.Items
.Cast<ListViewItem>()
.Where(i => i.Checked)
.Select(i => (string)i.Tag)
.ToList();
schema.Normalize();
if ((_schemas.Items ?? new List<TemplateSchemaDefinition>())
.Any(x => !ReferenceEquals(x, schema) && string.Equals(x.TemplateKey, schema.TemplateKey, StringComparison.OrdinalIgnoreCase)))
{
MessageBox.Show(this, "保存失败:存在重复的四参数组合。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
TemplateSchemaStore.Save(_schemas);
MessageBox.Show(this, "已保存。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
ReloadSchemaList();
}
catch (Exception ex)
{
MessageBox.Show(this, $"保存失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}