using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Collections.ObjectModel;
namespace DrillTools
{
///
/// Interaction logic for App.xaml
///
public partial class App : System.Windows.Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
RegisterShellContextMenu();
string? filePath = null;
if (e.Args.Length > 0)
{
filePath = e.Args[0];
if (!IsValidDrillTapeFile(filePath))
filePath = null;
}
if (filePath == null)
{
ShowMainWindow(null);
return;
}
// 防止选择窗口关闭后触发 OnLastWindowClose 导致应用退出
ShutdownMode = ShutdownMode.OnExplicitShutdown;
// 只读取和解析文件一次,提取所有需要的信息
string content = CommandTypeFileReader.ReadAllText(filePath);
var viewModel = new MainWindowViewModel
{
IsStartupDrillTapeFile = true,
OriginalFilePath = filePath,
ShouldCheckSortFileOnLoad = false
};
viewModel.LoadToolsFromDrillTape(content);
bool canClearParameters = DrillTapeParameterCleaner.CanClearParameters(content);
bool canGeneratePpDrillTape = viewModel.CanGeneratePpDrillTape;
string extension = Path.GetExtension(filePath).ToLowerInvariant();
bool canScaleDrillTape = extension == ".dr2" || extension == ".dpin";
double minDrill = viewModel.MinDrillDiameter;
double minSlot = viewModel.MinSlotDiameter;
double minEA = viewModel.MinEADiameter;
bool isPpDrillTape = viewModel.IsPpDrillTape;
double ppXSpacing = viewModel.PpXSpacing;
double ppYSpacing = viewModel.PpYSpacing;
bool hasOuter3175Spacing = viewModel.HasOuter3175Spacing;
double outer3175XSpacing = viewModel.Outer3175XSpacing;
double outer3175YSpacing = viewModel.Outer3175YSpacing;
var selectionViewModel = new StartupSelectionViewModel
{
FileName = Path.GetFileNameWithoutExtension(filePath),
MinDrillDiameter = minDrill,
MinSlotDiameter = minSlot,
MinEADiameter = minEA,
IsPpDrillTape = isPpDrillTape,
PpXSpacing = ppXSpacing,
PpYSpacing = ppYSpacing,
HasOuter3175Spacing = hasOuter3175Spacing,
Outer3175XSpacing = outer3175XSpacing,
Outer3175YSpacing = outer3175YSpacing
};
// 叠板计算用的最小刀径独立遍历 Tools 计算,包含 0.749mm
CalculateStackMinDiameters(viewModel.Tools, selectionViewModel);
var selectionWindow = new StartupSelectionWindow(
selectionViewModel,
canClearParameters,
canGeneratePpDrillTape,
canScaleDrillTape);
selectionWindow.ShowDialog();
switch (selectionWindow.SelectedAction)
{
case StartupAction.AdjustToolOrder:
ShutdownMode = ShutdownMode.OnLastWindowClose;
ShowMainWindow(filePath);
break;
case StartupAction.ExportHoleCount:
PerformHeadlessExport(filePath);
Shutdown();
break;
case StartupAction.ClearParameters:
PerformParameterCleanup(filePath);
Shutdown();
break;
case StartupAction.GeneratePpDrillTape:
PerformPpDrillTapeGeneration(filePath);
Shutdown();
break;
case StartupAction.ScaleDrillTape:
PerformDrillScaling(filePath);
Shutdown();
break;
default:
Shutdown();
break;
}
}
private static void ShowMainWindow(string? filePath)
{
try
{
MainWindow mainWindow = new MainWindow(filePath);
mainWindow.Show();
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"创建MainWindow时发生异常:\n{ex.GetType().Name} - {ex.Message}\n\n{ex.StackTrace}",
"启动失败", MessageBoxButton.OK, MessageBoxImage.Error);
throw;
}
}
private static void PerformHeadlessExport(string filePath)
{
try
{
var viewModel = new MainWindowViewModel
{
ShouldCheckSortFileOnLoad = false
};
string content = CommandTypeFileReader.ReadAllText(filePath);
viewModel.OriginalFilePath = filePath;
viewModel.LoadToolsFromDrillTape(content);
if (viewModel.Tools.Count == 0)
{
System.Windows.MessageBox.Show("钻带文件中未找到有效的刀具数据,无法导出孔数报表。",
"提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
viewModel.ExportDrillUsageReport();
}
catch (OperationCanceledException)
{
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"导出孔数报表失败:\n{ex.Message}",
"错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private static void PerformPpDrillTapeGeneration(string filePath)
{
try
{
var viewModel = new MainWindowViewModel
{
IsStartupDrillTapeFile = true,
OriginalFilePath = filePath,
ShouldCheckSortFileOnLoad = false
};
string content = CommandTypeFileReader.ReadAllText(filePath);
viewModel.LoadToolsFromDrillTape(content);
string outputFilePath = viewModel.GeneratePpDrillTape();
System.Windows.MessageBox.Show(
$"PP钻带已生成:\n{outputFilePath}",
"生成PP钻带完成",
MessageBoxButton.OK,
MessageBoxImage.Information);
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"生成PP钻带失败:\n{ex.Message}",
"错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private static void PerformParameterCleanup(string filePath)
{
try
{
DrillTapeParameterCleaner.ClearParametersAndSave(filePath);
System.Windows.MessageBox.Show(
$"参数已清空,原文件已备份为:\n{Path.GetFileName(filePath)}.bak",
"清空参数完成",
MessageBoxButton.OK,
MessageBoxImage.Information);
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"清空参数失败:\n{ex.Message}",
"错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private static void PerformDrillScaling(string filePath)
{
try
{
var scalingWindow = new DrillScalingWindow();
scalingWindow.ShowDialog();
if (scalingWindow.ScalingResult == null)
return;
var result = scalingWindow.ScalingResult.Value;
string content = CommandTypeFileReader.ReadAllText(filePath);
string scaledContent = Integration.ExcellonScaler.Scale(content, result.Kx, result.Ky);
// 备份原文件
string backupFilePath = filePath + ".bak";
File.Copy(filePath, backupFilePath, true);
// 写入缩放后的内容
using var writer = new StreamWriter(filePath, false, Encoding.GetEncoding(936));
writer.Write(scaledContent);
// 系数记忆:紧跟钻带写回立即落盘,不滞后到完成提示之后。
// 属辅助功能,失败不回滚已完成的涨缩,失败原因随完成提示一并告知。
string? memoryWarning = null;
try
{
ScalingProfileStore.Save(result.Mode, result.InputX, result.InputY, Path.GetFileName(filePath));
}
catch (Exception ex)
{
memoryWarning = $"\n(系数记忆保存失败:{ex.Message})";
}
string completionMessage = $"涨缩完成,原文件已备份为:\n{Path.GetFileName(filePath)}.bak";
if (memoryWarning != null)
completionMessage += memoryWarning;
System.Windows.MessageBox.Show(
completionMessage,
"涨缩完成",
MessageBoxButton.OK,
MessageBoxImage.Information);
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"涨缩失败:\n{ex.Message}",
"错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private static void RegisterShellContextMenu()
{
try
{
string exePath = Process.GetCurrentProcess().MainModule!.FileName!;
string[] extensions = { ".drl", ".dr2", ".dr3", ".trg", ".dpin", ".txt" };
string menuText = "用DrillTools打开";
foreach (string ext in extensions)
{
string keyPath = $@"SystemFileAssociations\{ext}\shell\{menuText}\command";
using var key = Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(keyPath);
key.SetValue("", $"\"{exePath}\" \"%1\"");
}
}
catch
{
// 非管理员权限时注册可能失败,静默忽略不影响主功能
}
}
///
/// 验证是否为有效的钻带文件
///
/// 文件路径
/// 是否为有效钻带文件
private static bool IsValidDrillTapeFile(string filePath)
{
if (string.IsNullOrEmpty(filePath))
return false;
if (!File.Exists(filePath))
return false;
// 检查文件扩展名是否为支持的钻带文件格式
string extension = Path.GetExtension(filePath).ToLowerInvariant();
string[] supportedExtensions = { ".txt", ".drl", ".dr2", ".dr3", ".trg", ".dpin" };
return supportedExtensions.Contains(extension);
}
///
/// 从 MainWindowViewModel.Tools 独立遍历计算叠板用最小刀径。
/// 分类逻辑与 UpdateMinDiameterInfo 一致(按 ToolType 区分圆孔/槽孔),不排除 0.749mm;
/// 特殊固定孔径(3.203 等)不参与叠板计算。
///
private static void CalculateStackMinDiameters(
ObservableCollection tools,
StartupSelectionViewModel selectionViewModel)
{
double minDrill = 0;
double minSlot = 0;
double minEA = 0;
foreach (var tool in tools)
{
if (tool.ToolType == ToolType.MachineCode)
continue;
if (ToolItem.IsSpecialFixedDiameter(tool.Diameter))
continue;
if (tool.ToolType == ToolType.Regular)
{
if (minDrill == 0 || tool.Diameter < minDrill)
minDrill = tool.Diameter;
}
else if (tool.ToolType == ToolType.Slot)
{
if (tool.ToolSuffixType != ToolSuffixType.EASlot && tool.ToolSuffixType != ToolSuffixType.EASlot2)
{
if (minSlot == 0 || tool.Diameter < minSlot)
minSlot = tool.Diameter;
}
if ((tool.ToolSuffixType == ToolSuffixType.EASlot || tool.ToolSuffixType == ToolSuffixType.EASlot2)
&& (minEA == 0 || tool.Diameter < minEA))
{
minEA = tool.Diameter;
}
}
}
selectionViewModel.StackCalcMinDrill = minDrill;
selectionViewModel.StackCalcMinSlot = minSlot;
selectionViewModel.StackCalcMinEA = minEA;
}
}
}