feat: 二钻涨缩系数记忆,载入上次系数

涨缩完成后将模式与系数写入 %LocalAppData%\DrillTools\scaling.ini,涨缩窗口新增"载入上次系数"按钮实时读取回填。每次完成涨缩覆盖更新,只保留最新一条记录(含源文件名追溯)。ini 使用 UTF-8 无 BOM,损坏时容错返回空。
This commit is contained in:
2026-06-14 12:16:17 +08:00
parent 906de9e265
commit 29c7be3fac
4 changed files with 181 additions and 5 deletions

View File

@@ -208,10 +208,10 @@ namespace DrillTools
if (scalingWindow.ScalingResult == null) if (scalingWindow.ScalingResult == null)
return; return;
var (kx, ky) = scalingWindow.ScalingResult.Value; var result = scalingWindow.ScalingResult.Value;
string content = CommandTypeFileReader.ReadAllText(filePath); string content = CommandTypeFileReader.ReadAllText(filePath);
string scaledContent = Integration.ExcellonScaler.Scale(content, kx, ky); string scaledContent = Integration.ExcellonScaler.Scale(content, result.Kx, result.Ky);
// 备份原文件 // 备份原文件
string backupFilePath = filePath + ".bak"; string backupFilePath = filePath + ".bak";
@@ -226,6 +226,19 @@ namespace DrillTools
"涨缩完成", "涨缩完成",
MessageBoxButton.OK, MessageBoxButton.OK,
MessageBoxImage.Information); MessageBoxImage.Information);
// 系数记忆:将本次模式与原始输入连同源文件名写入 ini供下次载入。
// 属辅助功能,失败不回滚已完成的涨缩,单独提示。
try
{
ScalingProfileStore.Save(result.Mode, result.InputX, result.InputY, Path.GetFileName(filePath));
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(
$"系数记忆保存失败:\n{ex.Message}\n本次涨缩已完成不影响结果。",
"系数记忆", MessageBoxButton.OK, MessageBoxImage.Warning);
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -82,6 +82,12 @@
<StackPanel Grid.Row="4" <StackPanel Grid.Row="4"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Orientation="Horizontal"> Orientation="Horizontal">
<Button Name="LoadLastButton"
Width="110"
Height="30"
Content="载入上次系数"
Margin="0,0,10,0"
Click="LoadLastButton_Click" />
<Button Width="80" <Button Width="80"
Height="30" Height="30"
Content="取消" Content="取消"

View File

@@ -10,9 +10,10 @@ namespace DrillTools
private readonly DrillScalingViewModel _viewModel; private readonly DrillScalingViewModel _viewModel;
/// <summary> /// <summary>
/// 用户确认后的缩放结果kx, ky /// 用户确认后的缩放结果
/// 保留模式与原始输入(用于系数记忆落盘),同时携带换算后的倍率(用于实际缩放)。
/// </summary> /// </summary>
public (double Kx, double Ky)? ScalingResult { get; private set; } public (ScalingMode Mode, string InputX, string InputY, double Kx, double Ky)? ScalingResult { get; private set; }
public DrillScalingWindow() public DrillScalingWindow()
{ {
@@ -42,11 +43,42 @@ namespace DrillTools
return; return;
} }
ScalingResult = (_viewModel.Kx, _viewModel.Ky); ScalingResult = (_viewModel.Mode, _viewModel.InputX, _viewModel.InputY, _viewModel.Kx, _viewModel.Ky);
DialogResult = true; DialogResult = true;
Close(); Close();
} }
/// <summary>
/// 载入上次涨缩系数:实时读取 ini 并回填模式与输入框。
/// RadioButton 与 Mode 为单向事件绑定,模式回填需手动同步 RadioButton 状态。
/// </summary>
private void LoadLastButton_Click(object sender, RoutedEventArgs e)
{
try
{
var record = ScalingProfileStore.Load();
if (record == null)
{
System.Windows.MessageBox.Show("没有可载入的上次系数记录。", "载入上次系数",
MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
// 先同步 RadioButton设目标项为 true靠同组互斥取消另一项并触发 ModeRadioButton_Changed 联动 Mode 与派生标签),再回填输入框
if (record.Mode == ScalingMode.Ratio)
RatioRadioButton.IsChecked = true;
else
PpmRadioButton.IsChecked = true;
_viewModel.InputX = record.InputX;
_viewModel.InputY = record.InputY;
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"载入上次系数失败:\n{ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void CancelButton_Click(object sender, RoutedEventArgs e) private void CancelButton_Click(object sender, RoutedEventArgs e)
{ {
ScalingResult = null; ScalingResult = null;

125
ScalingProfileStore.cs Normal file
View File

@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace DrillTools
{
/// <summary>
/// 二钻涨缩系数的 ini 持久化存储。
/// 存放于 %LocalAppData%\DrillTools\scaling.iniUTF-8 无 BOM
/// 只保留最近一次涨缩记录(模式 + 输入值 + 源文件名)。
/// </summary>
internal static class ScalingProfileStore
{
private const string SectionName = "LastScaling";
private const string KeyMode = "Mode";
private const string KeyInputX = "InputX";
private const string KeyInputY = "InputY";
private const string KeyFileName = "FileName";
/// <summary>
/// ini 配置文件完整路径:%LocalAppData%\DrillTools\scaling.ini
/// </summary>
private static string GetIniPath()
{
string dir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"DrillTools");
return Path.Combine(dir, "scaling.ini");
}
/// <summary>
/// 读取上次涨缩记录。
/// 文件不存在或缺少必需键(含模式无法解析)时返回 null其它 IO 异常向上抛出,由调用边界处理。
/// </summary>
public static ScalingRecord? Load()
{
string path = GetIniPath();
if (!File.Exists(path))
return null;
// 简易 ini 解析:按 [section] 切节,仅在目标节内收集 key=value
var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
bool inSection = false;
foreach (var raw in File.ReadAllLines(path))
{
string line = raw.Trim();
if (line.Length == 0 || line.StartsWith(";"))
continue;
// 节标题
if (line.StartsWith("[") && line.EndsWith("]"))
{
inSection = line.Equals($"[{SectionName}]", StringComparison.OrdinalIgnoreCase);
continue;
}
if (!inSection)
continue;
int eq = line.IndexOf('=');
if (eq <= 0)
continue;
string key = line.Substring(0, eq).Trim();
string val = line.Substring(eq + 1).Trim();
values[key] = val;
}
// 必需键校验:缺任一或模式无法解析视为无有效记录(容错损坏)
if (!values.TryGetValue(KeyMode, out string? modeStr) ||
!values.TryGetValue(KeyInputX, out string? inputX) ||
!values.TryGetValue(KeyInputY, out string? inputY))
return null;
if (!Enum.TryParse(modeStr, out ScalingMode mode))
return null;
// 文件名为可选追溯字段
values.TryGetValue(KeyFileName, out string? fileName);
return new ScalingRecord(mode, inputX, inputY, fileName);
}
/// <summary>
/// 写入涨缩记录,整体覆盖。自动创建目录。失败时抛出异常,由调用边界处理。
/// </summary>
public static void Save(ScalingMode mode, string inputX, string inputY, string fileName)
{
string path = GetIniPath();
string? dir = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(dir))
Directory.CreateDirectory(dir);
var content =
$"[{SectionName}]\r\n" +
$"{KeyMode}={mode}\r\n" +
$"{KeyInputX}={inputX}\r\n" +
$"{KeyInputY}={inputY}\r\n" +
$"{KeyFileName}={fileName}\r\n";
// UTF-8 无 BOM项目文件编码规范
File.WriteAllText(path, content, new UTF8Encoding(false));
}
}
/// <summary>
/// 涨缩系数持久化记录(只读)。
/// </summary>
internal sealed class ScalingRecord
{
public ScalingMode Mode { get; }
public string InputX { get; }
public string InputY { get; }
public string? FileName { get; }
public ScalingRecord(ScalingMode mode, string inputX, string inputY, string? fileName)
{
Mode = mode;
InputX = inputX;
InputY = inputY;
FileName = fileName;
}
}
}