CadParamPluging/UI/ParamDrawingPanel.cs

848 lines
37 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.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using CadParamPluging.Cad;
using CadParamPluging.Common;
using CadParamPluging.Domain;
using CadParamPluging.Domain.Models;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace CadParamPluging.UI
{
public class ParamDrawingPanel : UserControl
{
private readonly ComboBox _cbProjectType;
private readonly ComboBox _cbDrawingType;
private readonly ComboBox _cbSheetSize;
private readonly ComboBox _cbScale;
private TextBox _txtLog;
public ParamDrawingPanel()
{
Dock = DockStyle.Fill;
var dropdownOptions = DropdownOptionsStore.Load();
var layout = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 1,
RowCount = 4,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink,
Padding = new Padding(8)
};
_cbProjectType = CreateComboBox(dropdownOptions.DeliveryStatuses);
_cbDrawingType = CreateComboBox(dropdownOptions.ProcessMethods);
_cbSheetSize = CreateComboBox(dropdownOptions.StructuralFeatures);
_cbScale = CreateComboBox(dropdownOptions.SpecialConditions);
// Initialize template controls here in constructor to follow readonly/non-readonly best practices,
// though they are no longer readonly.
var templateGroup = BuildTemplateGroup();
var drawingGroup = BuildDrawingGroup();
var actionPanel = BuildActionPanel();
var logGroup = BuildLogGroup();
layout.Controls.Add(templateGroup, 0, 0);
layout.Controls.Add(drawingGroup, 0, 1);
layout.Controls.Add(actionPanel, 0, 2);
layout.Controls.Add(logGroup, 0, 3);
Controls.Add(layout);
}
private GroupBox BuildTemplateGroup()
{
var group = new GroupBox
{
Text = "模板参数",
Dock = DockStyle.Top,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink
};
var grid = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 4,
AutoSize = true
};
grid.Controls.Add(new Label { Text = "交付状态", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 0);
grid.Controls.Add(_cbProjectType, 1, 0);
grid.Controls.Add(new Label { Text = "工艺方法", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 1);
grid.Controls.Add(_cbDrawingType, 1, 1);
grid.Controls.Add(new Label { Text = "结构特征", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 2);
grid.Controls.Add(_cbSheetSize, 1, 2);
grid.Controls.Add(new Label { Text = "特殊条件", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 3);
grid.Controls.Add(_cbScale, 1, 3);
group.Controls.Add(grid);
return group;
}
private GroupBox BuildDrawingGroup()
{
var group = new GroupBox
{
Text = "出图参数",
Dock = DockStyle.Top,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink
};
var label = new Label
{
AutoSize = true,
Padding = new Padding(8),
Text = "出图参数较多,请点击【生成图纸】后在弹窗中填写。"
};
group.Controls.Add(label);
return group;
}
private FlowLayoutPanel BuildActionPanel()
{
var panel = new FlowLayoutPanel
{
Dock = DockStyle.Top,
AutoSize = true
};
var btnGenerate = new Button { Text = "生成图纸", AutoSize = true };
btnGenerate.Click += (_, __) => OnGenerateDrawing();
var btnSaveAs = new Button { Text = "保存当前图纸", AutoSize = true };
btnSaveAs.Click += (_, __) => OnSaveDrawing();
var btnSettings = new Button { Text = "设置", AutoSize = true };
btnSettings.Click += (_, __) => OnOpenSettings();
var btnTestDraw = new Button { Text = "测试绘制", AutoSize = true };
btnTestDraw.Click += (_, __) => OnTestDraw();
panel.Controls.Add(btnGenerate);
panel.Controls.Add(btnSaveAs);
var btnLoadParams = new Button { Text = "读取参数", AutoSize = true };
btnLoadParams.Click += (_, __) => OnLoadParams();
panel.Controls.Add(btnLoadParams);
panel.Controls.Add(btnSettings);
// panel.Controls.Add(btnTestDraw); // 暂时屏蔽测试绘制按钮
return panel;
}
private GroupBox BuildLogGroup()
{
var group = new GroupBox
{
Text = "日志",
Dock = DockStyle.Fill
};
_txtLog = new TextBox
{
Multiline = true,
ScrollBars = ScrollBars.Vertical,
Dock = DockStyle.Fill,
Height = 140
};
group.Controls.Add(_txtLog);
return group;
}
private static double ParseScaleFactor(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
{
throw new BusinessException("请填写:出图比例 (DrawingScale)");
}
var s = (raw ?? string.Empty).Trim();
s = s.Replace(" ", "").Replace("\u3000", "").Replace("", ":");
var parts = s.Split(':');
if (parts.Length != 2 || !string.Equals(parts[0], "1", StringComparison.OrdinalIgnoreCase))
{
throw new BusinessException("出图比例格式错误,应为 1:n例如 1:5");
}
if (!TryParseDouble(parts[1], out var denom) || denom < 1e-9)
{
throw new BusinessException("出图比例格式错误,应为 1:n例如 1:5");
}
if (denom < 1.0)
{
throw new BusinessException("出图比例不支持放大n 必须 >= 1");
}
return 1.0 / denom;
}
private static bool TryParseDouble(string s, out double value)
{
value = 0;
if (string.IsNullOrWhiteSpace(s))
{
return false;
}
return double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out value)
|| double.TryParse(s, NumberStyles.Float, CultureInfo.CurrentCulture, out value);
}
private void OnGenerateDrawing()
{
try
{
var tplParams = CollectTemplateParams();
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;
}
if (!TemplateDrawingRegistry.TryResolve(templateKey, out var generator))
{
AppendLog($"未找到该模板的图纸生成逻辑TemplateKey={templateKey})。请先实现对应模板生成器。");
return;
}
var catalog = ParamCatalogStore.Load();
CadParamPluging.Common.ParamBag bag;
// 若用户点击了【读取参数】,则将读取到的参数作为本次弹窗的默认值回填
using (var f = new DrawingParamsForm(catalog, schema, _lastLoadedBag))
{
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 = AcadApp.DocumentManager.MdiActiveDocument;
if (doc == null)
{
AppendLog("未检测到活动图纸,请先打开 CAD 图纸。");
return;
}
string layoutName = LayoutManager.Current.CurrentLayout;
// 判断是否模型空间。注意LayoutName为"Model"通常表示模型空间
bool isModelSpace = string.Equals(layoutName, "Model", StringComparison.OrdinalIgnoreCase);
AppendLog($"正在当前图纸生成: {doc.Name} ({layoutName})");
using (doc.LockDocument())
using (var ctx = new CadContext(doc))
{
// 用户要求保留模板配置文字,不执行移除操作
// var removed = TemplateDrawingService.RemoveMatchParameterAnnotations(
// ctx,
// layoutName,
// isModelSpace);
// if (removed > 0)
// {
// AppendLog($"已移除模板匹配参数标注文本: {removed} 处");
// }
var featureCategoryCount = TemplateDrawingService.ApplyFeatureCategory(
ctx,
layoutName,
isModelSpace,
bag,
msg => AppendLog(msg)); // 传递日志回调
if (featureCategoryCount > 0)
{
AppendLog($"已更新特性分类(******: {featureCategoryCount} 处");
}
var noteResult = TemplateDrawingService.ApplyNoteTemplate(
ctx,
layoutName,
isModelSpace,
schema,
bag);
if (noteResult != null)
{
if (noteResult.Applied)
{
AppendLog($"附注替换成功(目标={noteResult.TargetKind}, 占位符={noteResult.PlaceholderCountInDwg}");
}
else if (!string.IsNullOrWhiteSpace(noteResult.Message))
{
AppendLog($"附注替换跳过: {noteResult.Message}");
}
}
// 删除模板中原有的图纸图形CAXA图层和尺寸标注保留右上角
var removeResult = TemplateDrawingService.RemoveTemplateOriginalDrawing(ctx);
AppendLog($"已删除原有图形: 红色外框={removeResult.OuterFrameErased}, CAXA图层={removeResult.CaxaLayerErased}, 标注={removeResult.DimensionLayerErased}, 保留右上角={removeResult.DimensionLayerKept}");
// 删除白色线框内“上半部分”的所有内容(保留右上角与下半部分附注/表格)
var upperRemoved = TemplateDrawingService.RemoveWhiteFrameUpperContent(
ctx,
keepBottomRatio: 0.50,
topRightThreshold: 0.70);
if (upperRemoved > 0)
{
AppendLog($"已清理白框上半部内容: {upperRemoved} 处");
}
var scaleFactor = ParseScaleFactor(bag.GetString("DrawingScale"));
if (removeResult.WhiteFrameExtents.HasValue && removeResult.CaxaLayerErased == 0)
{
AppendLog($"未检测到CAXA层已切换至白框定位: {removeResult.OriginalCenter}");
}
else
{
AppendLog($"原图中心点: {removeResult.OriginalCenter}");
}
// ---------------------------------------------------------
// 智能比例建议 (Pre-calculation)
// ---------------------------------------------------------
if (removeResult.WhiteFrameExtents.HasValue)
{
var frame = removeResult.WhiteFrameExtents.Value;
var frameWidth = frame.MaxPoint.X - frame.MinPoint.X;
var frameHeight = frame.MaxPoint.Y - frame.MinPoint.Y;
// 确保 bag 中包含交付状态和工艺方法,以便 CalculateExpectedSize 正确判断示意图模式
// tplParams.ProjectType = 交付状态(如"车加工"tplParams.DrawingType = 工艺方法(如"轧制"
if (string.IsNullOrEmpty(bag.GetString("DeliveryStatus")))
{
bag.Set("DeliveryStatus", tplParams.ProjectType ?? string.Empty);
}
if (string.IsNullOrEmpty(bag.GetString("ProcessMethod")))
{
bag.Set("ProcessMethod", tplParams.DrawingType ?? string.Empty);
}
// 1. 获取预估图形尺寸 (不含标注的纯几何尺寸 + 预留边距)
var expectedSize = generator.CalculateExpectedSize(bag, tplParams);
// 调试:输出关键参数以排查比例建议错误
var debugDelivery = bag.GetString("DeliveryStatus");
var debugProcess = bag.GetString("ProcessMethod");
var debugMinWall = bag.GetDoubleOrNull("MinWallThickness");
var debugHeight = bag.GetDoubleOrNull("Height1");
var debugOuterDia = bag.GetDoubleOrNull("OuterDiameter1");
AppendLog($"[调试] 交付状态={debugDelivery}, 工艺方法={debugProcess}");
AppendLog($"[调试] 外径D1={debugOuterDia}, 高度H1={debugHeight}, 最小壁厚={debugMinWall}, 结构={tplParams.SheetSize}");
if (expectedSize.IsValid)
{
var currentDrawW = expectedSize.Width * scaleFactor;
var currentDrawH = expectedSize.Height * scaleFactor;
bool isOverflow = currentDrawW > frameWidth || currentDrawH > frameHeight;
bool isTooSmall = currentDrawW < frameWidth * 0.3 && currentDrawH < frameHeight * 0.3;
// 调试日志
AppendLog($"[尺寸检查] 白框尺寸: {frameWidth:F0}x{frameHeight:F0}, 预期图形(原始): {expectedSize.Width:F0}x{expectedSize.Height:F0}, 当前比例: 1:{(1/scaleFactor):F1}");
AppendLog($"[尺寸检查] 预期图形(缩放后): {currentDrawW:F0}x{currentDrawH:F0}, 超出={isOverflow}, 过小={isTooSmall}");
AppendLog($"[尺寸检查] 判断阈值: 超出条件(W>{frameWidth:F0} || H>{frameHeight:F0}), 过小条件(W<{frameWidth*0.3:F0} && H<{frameHeight*0.3:F0})");
if (isOverflow || isTooSmall)
{
// 计算建议比例 (目标填充率 65%)
var ratioW = frameWidth / expectedSize.Width;
var ratioH = frameHeight / expectedSize.Height;
var targetScale = Math.Min(ratioW, ratioH) * 0.65;
// 格式化建议比例
string suggestedScaleText;
double newOneToN = 1.0 / targetScale;
// 简单的取整逻辑,优先凑整 1:1, 1:2, 1:5, 1:10 等
if (targetScale >= 0.95)
{
suggestedScaleText = "1:1";
targetScale = 1.0;
}
else
{
// 凑整到最近的 0.5 或 整数
if (newOneToN < 10)
{
newOneToN = Math.Round(newOneToN * 2) / 2.0; // 凑整 0.5
}
else
{
newOneToN = Math.Round(newOneToN); // 凑整 1
}
suggestedScaleText = $"1:{newOneToN}";
targetScale = 1.0 / newOneToN;
}
var msg = isOverflow
? $"当前比例 (1:{(1/scaleFactor):F1}) 会导致图形超出图纸边框。\n建议调整为 {suggestedScaleText}。\n\n是否应用建议比例"
: $"当前比例 (1:{(1/scaleFactor):F1}) 会导致图形过小(占比<30%)。\n建议调整为 {suggestedScaleText}。\n\n是否应用建议比例";
var dialogResult = MessageBox.Show(this, msg, "自动比例建议", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (dialogResult == DialogResult.Yes)
{
scaleFactor = targetScale;
bag.Set("DrawingScale", suggestedScaleText); // 更新参数包中的比例字符串
AppendLog($"[自动调整] 已应用建议比例: {suggestedScaleText}");
}
else
{
AppendLog($"[自动调整] 用户忽略了比例建议,保持原比例。");
}
}
}
}
AppendLog($"绘图参数: Type={tplParams.ProjectType}, Size={tplParams.SheetSize}, Scale={bag.GetString("DrawingScale")}, Method={tplParams.DrawingType}");
// Dubug: Dump bag keys
var bagKeys = bag.GetKeys(); // Assuming GetKeys exists? If not, skip or use reflection?
// ParamBag implementation is simple dictionary usually.
// Let's just log specific keys we suspect.
AppendLog($"Bag Keys check: OD1={bag.GetDoubleOrNull("OuterDiameter1")}, H1={bag.GetDoubleOrNull("Height1")}");
// 根据模板参数绘制半剖视图,居中放置于原图纸位置
// 使用特征驱动模式:根据参数存在性动态绘制对应特征
generator.Draw(
ctx,
bag,
tplParams,
removeResult.OriginalCenter,
scaleFactor);
// Force Zoom Extents to ensure visibility
try { doc.SendStringToExecute("._ZOOM _E ", true, false, false); } catch { }
// 更新标题栏中的比例属性
var scaleUpdated = TemplateDrawingService.UpdateScaleAttribute(
ctx,
layoutName,
isModelSpace,
scaleFactor
);
if (scaleUpdated)
{
AppendLog($"已更新标题栏比例: {(scaleFactor >= 0.9999 ? "1:1" : $"1:{(1/scaleFactor):F1}")}");
}
else
{
AppendLog("未找到标题栏中的'比例'文字,无法更新比例");
}
// 更新标题栏中的检验类别
var inspectionCategory = bag.GetString("InspectionCategory");
if (!string.IsNullOrWhiteSpace(inspectionCategory))
{
var categoryUpdated = TemplateDrawingService.UpdateInspectionCategoryAttribute(
ctx,
layoutName,
isModelSpace,
inspectionCategory
);
if (categoryUpdated)
{
AppendLog($"已更新标题栏检验类别: {inspectionCategory}");
}
else
{
AppendLog("未找到标题栏中的'检验类别'文字,无法更新检验类别");
}
}
// 添加左上角"内部资料,控制范围"标记
var labelAdded = TemplateDrawingService.AddInternalMaterialLabel(
ctx, layoutName, isModelSpace);
if (labelAdded)
{
AppendLog("已添加内部资料标记");
}
ctx.Commit();
try { doc.Editor.Regen(); } catch { }
// 保存参数到图纸内部 (Extension Dictionary / NOD)
try
{
var bagToSave = bag;
// 保存面板选项
bagToSave.Set("ProjectType", tplParams.ProjectType);
bagToSave.Set("DrawingType", tplParams.DrawingType);
bagToSave.Set("SheetSize", tplParams.SheetSize);
bagToSave.Set("SpecialCondition", tplParams.Scale); // tplParams.Scale 对应 _cbScale (特殊条件)
DictionaryHelper.SaveParams(doc.Database, bagToSave);
AppendLog("参数已保存到图纸内部数据中。");
}
catch (Exception ex)
{
AppendLog($"保存内部参数失败: {ex.Message}");
Logger.Error("SaveParamsInternal", ex);
}
}
AppendLog("图纸生成完成。");
}
catch (BusinessException bex)
{
AppendLog($"参数错误: {bex.Message}");
}
catch (Exception ex)
{
AppendLog($"生成失败: {ex.Message}");
Logger.Error("GenerateDrawing", ex);
}
}
private void OnSaveDrawing()
{
try
{
var doc = AcadApp.DocumentManager.MdiActiveDocument;
if (doc == null)
{
AppendLog("未找到活动图纸,无法保存。");
return;
}
using (var dialog = new SaveFileDialog
{
Filter = "AutoCAD Drawing (*.dwg)|*.dwg",
FileName = "新图纸.dwg"
})
{
if (dialog.ShowDialog() == DialogResult.OK)
{
doc.Database.SaveAs(dialog.FileName, true, DwgVersion.Current, doc.Database.SecurityParameters);
AppendLog($"图纸已保存到: {dialog.FileName}");
}
}
}
catch (Exception ex)
{
AppendLog($"保存失败: {ex.Message}");
Logger.Error("SaveDrawing", ex);
}
}
private void OnOpenSettings()
{
try
{
var current = DropdownOptionsStore.Load();
using (var form = new SettingsForm(current))
{
if (form.ShowDialog() == DialogResult.OK)
{
DropdownOptionsStore.Save(form.Result);
ReloadDropdownOptions(form.Result);
AppendLog("设置已保存");
}
}
}
catch (Exception ex)
{
AppendLog($"打开设置失败: {ex.Message}");
Logger.Error("OpenSettings", ex);
}
}
private void OnLoadParams()
{
try
{
var doc = AcadApp.DocumentManager.MdiActiveDocument;
if (doc == null)
{
AppendLog("未找到活动图纸,无法读取参数。");
return;
}
ParamBag bag;
using (doc.LockDocument())
{
bag = DictionaryHelper.ReadParams(doc.Database);
}
if (bag == null || bag.Items == null || bag.Items.Count == 0)
{
AppendLog("当前图纸未找到存储的参数(或非本插件生成)。");
return;
}
// 2. 恢复下拉框选项
// ProjectType
TrySelectRequest(bag, "ProjectType", _cbProjectType);
// DrawingType
TrySelectRequest(bag, "DrawingType", _cbDrawingType);
// SheetSize
TrySelectRequest(bag, "SheetSize", _cbSheetSize);
// Scale (DrawingScale) - 注意我们下拉框叫 _cbScale参数里可能是 DrawingScale
var scaleVal = bag.GetString("DrawingScale");
// 特殊条件/Scale 其实是一个 ComboBox通常用于 SpecialConditions
// 但 DrawingScale 是在生成时 Parse 出来的。
// 这里的 _cbScale 绑定的是 options.SpecialConditions (e.g. "中心冲孔") 还是 "1:50"?
// 回看代码 reset _cbScale 绑定的是 options.SpecialConditions (ResetComboBoxItems(_cbScale, options.SpecialConditions))
// 而 "scale" 是指比例。
// 观察 GenerateDrawing 逻辑:
// var tplParams = CollectTemplateParams(); -> Scale = _cbScale.Text
// 这个 _cbScale 存的是“特殊条件”。
// 真正的比例是在 Bag.GetString("DrawingScale"),这是在 DrawParamsForm 里填写的。
//
// 等等!看 Readme 和 UI 逻辑,主面板只有 4 个下拉框: Project/Drawing/SheetSize/Scale
// 其中 _cbScale 有时候被用作 Scale但 DropdownOptions 绑定的是 SpecialConditions?
// Let's check ReloadDropdownOptions:
// ResetComboBoxItems(_cbScale, options.SpecialConditions); -> 所以 _cbScale 是“特殊条件”!
// 那比例去哪了?
// Readme 说 "ComboBox / TextBox比例Scale"
// 让我们确认 CollectTemplateParams: Scale = _cbScale.Text (specialCondition)
// 看来目前主面板并没有“比例”输入框?比例是在 Form 里填写的?
// 检查 OnGenerateDrawing -> new DrawingParamsForm(catalog, schema) -> 这个 Form 里填写的具体参数。
//
// 所以OnLoadParams 只能恢复 面板上的 4 个下拉框。
// 而 Form 里的参数(如 OuterDiameter, DrawingScale需要在点“生成”后弹出 Form 时自动填入。
// 这需要修改 DrawingParamsForm 的构造函数或者逻辑,让它支持“默认值”从 Bag 中覆盖。
TrySelectRequest(bag, "SpecialCondition", _cbScale); // 假设存的时候 key 是 SpecialCondition?
// CollectTemplateParams 里没有把 template params 放入 bag。
// 但是DomainFacade.ValidateParameters 可能会用到。
// 关键点TemplateParams 只是用来匹配 TemplateKey。
// 实际生成图纸时OnGenerateDrawing 收集了 tplParams然后 Build TemplateKey然后 Load Schema然后...
// 用 Form 填写了 Bag。
// 所以“项目类型/图纸类型”等并没有被存入 Bag (除非 Form 里也有对应字段)。
// 这是一个问题Bag 主要是 Form 的结果。面板上的选择决定了 TemplateKey。
// 我们在 SaveParamsToExtensionDictionary 时,只存了 Bag。
// 如果面板上的选项(项目类型等)没在 Bag 里,我们就无法恢复面板状态!
//
// 补救措施:必须在 SaveParams 时把 tplParams 的内容也塞进 Bag。
// 我刚刚加了 _TemplatePath/_LayoutName但漏了 ProjectType 等。
//
// 既然现在代码还没运行,我可以再加几个 Set。
AppendLog("参数读取完成。请点击【生成图纸】继续修改详细参数。");
// 将读取到的 Bag 暂存,以便 DrawingParamsForm 打开时使用它作为默认值
_lastLoadedBag = bag;
}
catch (Exception ex)
{
AppendLog($"读取参数失败: {ex.Message}");
Logger.Error("LoadParams", ex);
}
}
private ParamBag _lastLoadedBag; // 暂存读取到的参数
private void TrySelectRequest(ParamBag bag, string key, ComboBox cb)
{
var val = bag.GetString(key);
if (!string.IsNullOrEmpty(val))
{
// 尝试选中
int idx = cb.FindStringExact(val);
if (idx >= 0)
{
cb.SelectedIndex = idx;
return;
}
// 如果没有,可能手动 Text? ComboBoxStyle.DropDownList 不允许。
// 如果是 DropDownList 且不在列表中,就无法选中。
}
}
private void ReloadDropdownOptions(DropdownOptions options)
{
if (options == null)
{
return;
}
ResetComboBoxItems(_cbProjectType, options.DeliveryStatuses);
ResetComboBoxItems(_cbDrawingType, options.ProcessMethods);
ResetComboBoxItems(_cbSheetSize, options.StructuralFeatures);
ResetComboBoxItems(_cbScale, options.SpecialConditions);
}
private TemplateParams CollectTemplateParams()
{
var specialCondition = _cbScale.Text?.Trim();
if (string.Equals(specialCondition, "无", StringComparison.OrdinalIgnoreCase))
{
specialCondition = null;
}
return new TemplateParams
{
ProjectType = _cbProjectType.Text?.Trim(),
DrawingType = _cbDrawingType.Text?.Trim(),
SheetSize = _cbSheetSize.Text?.Trim(),
Scale = specialCondition
};
}
private static ComboBox CreateComboBox(System.Collections.Generic.IEnumerable<string> items)
{
var cb = new ComboBox
{
DropDownStyle = ComboBoxStyle.DropDownList,
Width = 160
};
var arr = (items ?? Enumerable.Empty<string>()).Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).ToArray();
if (arr.Length > 0)
{
cb.Items.AddRange(arr);
}
if (cb.Items.Count > 0)
{
cb.SelectedIndex = 0;
}
return cb;
}
private static void ResetComboBoxItems(ComboBox cb, System.Collections.Generic.IEnumerable<string> items)
{
if (cb == null)
{
return;
}
var previous = cb.Text;
var arr = (items ?? Enumerable.Empty<string>()).Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).ToArray();
cb.BeginUpdate();
try
{
cb.Items.Clear();
if (arr.Length > 0)
{
cb.Items.AddRange(arr);
var idx = Array.FindIndex(arr, v => string.Equals(v, previous, StringComparison.OrdinalIgnoreCase));
cb.SelectedIndex = idx >= 0 ? idx : 0;
}
}
finally
{
cb.EndUpdate();
}
}
private void OnTestDraw()
{
try
{
// ==========================================
// 测试参数构造 - 演示特征驱动模式
// ==========================================
var bag = new ParamBag();
// 锻件参数 (调整为细长型,符合参考图比例)
bag.Set("OuterDiameter1", "160");
bag.Set("OuterDiameter1TolPlus", "2");
bag.Set("OuterDiameter1TolMinus", "-2");
bag.Set("InnerDiameter2", "100");
bag.Set("InnerDiameter2TolPlus", "3");
bag.Set("InnerDiameter2TolMinus", "-3");
bag.Set("Height1", "400");
bag.Set("Height1TolPlus", "5");
bag.Set("Height1TolMinus", "-5");
// 零件参数 (车加工)
bag.Set("OuterDiameter1Prime", "150");
bag.Set("InnerDiameter2Prime", "110");
bag.Set("Height1Prime", "380");
// 可选特征参数 - 根据模板绑定动态显示
bag.Set("UnspecifiedFilletRadiusMax", "6"); // 未注圆角半径R≤6
bag.Set("MinWallThickness", "25"); // 最小壁厚T
// bag.Set("InnerRadiusMax", "8"); // 内径半径R≤8中心冲孔时用
var doc = AcadApp.DocumentManager.MdiActiveDocument;
if (doc == null)
{
AppendLog("未找到活动图纸。");
return;
}
using (doc.LockDocument())
using (var ctx = new CadContext(doc))
{
// 调用特征驱动绘图引擎
// 会根据bag中存在的参数自动绘制对应特征
HalfSectionDrawer.Draw(
ctx,
bag,
"车加工", // 交付状态
"环形", // 结构特征
null // 特殊条件(可选:中心冲孔/有圆头等)
);
ctx.Commit();
AppendLog($"测试绘制完成 (特征驱动模式)");
AppendLog($"已绘制特征: 外轮廓、内孔(虚线)、公差标注、未注圆角、壁厚、零件(填充)");
}
// Zoom Extents
doc.SendStringToExecute("._ZOOM _E ", true, false, false);
}
catch (Exception ex)
{
AppendLog($"测试绘制失败: {ex.Message}");
Logger.Error("TestDraw", ex);
}
}
private void AppendLog(string message)
{
var time = DateTime.Now.ToString("HH:mm:ss");
_txtLog.AppendText($"[{time}] {message}{Environment.NewLine}");
}
}
}