feat: 二钻涨缩系数记忆,载入上次系数
涨缩完成后将模式与系数写入 %LocalAppData%\DrillTools\scaling.ini,涨缩窗口新增"载入上次系数"按钮实时读取回填。每次完成涨缩覆盖更新,只保留最新一条记录(含源文件名追溯)。ini 使用 UTF-8 无 BOM,损坏时容错返回空。
This commit is contained in:
17
App.xaml.cs
17
App.xaml.cs
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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="取消"
|
||||||
|
|||||||
@@ -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
125
ScalingProfileStore.cs
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DrillTools
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 二钻涨缩系数的 ini 持久化存储。
|
||||||
|
/// 存放于 %LocalAppData%\DrillTools\scaling.ini,UTF-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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user