From baa9e1003ef1154e3dc852103e37e9e2b7dc2cc7 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 27 Jul 2025 22:00:37 +0800
Subject: [PATCH 1/9] fix:issue #93
---
.../MainWindow_cs/MW_FloatingBarIcons.cs | 6 ++
Ink Canvas/MainWindow_cs/MW_Settings.cs | 12 +++-
Ink Canvas/MainWindow_cs/MW_TouchEvents.cs | 67 ++++++++++++++++++-
3 files changed, 79 insertions(+), 6 deletions(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index 37fcd6cf..251d0b0e 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -1726,7 +1726,11 @@ namespace Ink_Canvas {
}
ClearStrokes(false);
+ // 保存非笔画元素(如图片)
+ var preservedElements = PreserveNonStrokeElements();
inkCanvas.Children.Clear();
+ // 恢复非笔画元素
+ RestoreNonStrokeElements(preservedElements);
CancelSingleFingerDragMode();
@@ -2021,5 +2025,7 @@ namespace Ink_Canvas {
}
}
}
+
+
}
}
diff --git a/Ink Canvas/MainWindow_cs/MW_Settings.cs b/Ink Canvas/MainWindow_cs/MW_Settings.cs
index bffec901..93f84f04 100644
--- a/Ink Canvas/MainWindow_cs/MW_Settings.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Settings.cs
@@ -1507,18 +1507,22 @@ namespace Ink_Canvas {
InkCanvasEditingMode currentEditingMode = inkCanvas.EditingMode;
int currentDrawingShapeMode = drawingShapeMode;
bool currentForceEraser = forceEraser;
-
+
inkCanvas.StylusDown -= MainWindow_StylusDown;
inkCanvas.StylusMove -= MainWindow_StylusMove;
inkCanvas.StylusUp -= MainWindow_StylusUp;
inkCanvas.TouchDown -= MainWindow_TouchDown;
inkCanvas.TouchDown += Main_Grid_TouchDown;
-
+
// 先设为None再设回原来的模式,避免可能的事件冲突
inkCanvas.EditingMode = InkCanvasEditingMode.None;
+ // 保存非笔画元素(如图片)
+ var preservedElements = PreserveNonStrokeElements();
inkCanvas.Children.Clear();
+ // 恢复非笔画元素
+ RestoreNonStrokeElements(preservedElements);
isInMultiTouchMode = false;
-
+
// 恢复到之前的编辑状态
inkCanvas.EditingMode = currentEditingMode;
drawingShapeMode = currentDrawingShapeMode;
@@ -2247,5 +2251,7 @@ namespace Ink_Canvas {
Settings.Canvas.EnablePalmEraser = ToggleSwitchEnablePalmEraser.IsOn;
SaveSettingsToFile();
}
+
+
}
}
diff --git a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
index 0212112c..7f803d2d 100644
--- a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
+++ b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
@@ -21,6 +21,46 @@ namespace Ink_Canvas {
private Point centerPoint = new Point(0, 0);
private InkCanvasEditingMode lastInkCanvasEditingMode = InkCanvasEditingMode.Ink;
+ ///
+ /// 保存画布上的非笔画元素(如图片、媒体元素等)
+ ///
+ private List PreserveNonStrokeElements()
+ {
+ var preservedElements = new List();
+
+ // 遍历inkCanvas的所有子元素
+ for (int i = inkCanvas.Children.Count - 1; i >= 0; i--)
+ {
+ var child = inkCanvas.Children[i];
+
+ // 保存图片、媒体元素等非笔画相关的UI元素
+ if (child is Image || child is MediaElement ||
+ (child is Border border && border.Name != "AdvancedEraserOverlay"))
+ {
+ preservedElements.Add(child);
+ }
+ }
+
+ return preservedElements;
+ }
+
+ ///
+ /// 恢复之前保存的非笔画元素到画布
+ ///
+ private void RestoreNonStrokeElements(List preservedElements)
+ {
+ if (preservedElements == null) return;
+
+ foreach (var element in preservedElements)
+ {
+ // 确保元素没有父容器再添加到inkCanvas
+ if (element is FrameworkElement fe && fe.Parent == null)
+ {
+ inkCanvas.Children.Add(element);
+ }
+ }
+ }
+
private void BorderMultiTouchMode_MouseUp(object sender, MouseButtonEventArgs e) {
if (isInMultiTouchMode) {
inkCanvas.StylusDown -= MainWindow_StylusDown;
@@ -31,12 +71,16 @@ namespace Ink_Canvas {
if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint) {
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
}
+ // 保存非笔画元素(如图片)
+ var preservedElements = PreserveNonStrokeElements();
inkCanvas.Children.Clear();
+ // 恢复非笔画元素
+ RestoreNonStrokeElements(preservedElements);
isInMultiTouchMode = false;
-
+
}
else {
-
+
inkCanvas.StylusDown += MainWindow_StylusDown;
inkCanvas.StylusMove += MainWindow_StylusMove;
inkCanvas.StylusUp += MainWindow_StylusUp;
@@ -45,7 +89,11 @@ namespace Ink_Canvas {
if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint) {
inkCanvas.EditingMode = InkCanvasEditingMode.None;
}
+ // 保存非笔画元素(如图片)
+ var preservedElements = PreserveNonStrokeElements();
inkCanvas.Children.Clear();
+ // 恢复非笔画元素
+ RestoreNonStrokeElements(preservedElements);
isInMultiTouchMode = true;
}
}
@@ -118,7 +166,12 @@ namespace Ink_Canvas {
VisualCanvasList.Remove(e.StylusDevice.Id);
TouchDownPointsList.Remove(e.StylusDevice.Id);
if (StrokeVisualList.Count == 0 || VisualCanvasList.Count == 0 || TouchDownPointsList.Count == 0) {
- inkCanvas.Children.Clear();
+ // 只清除手写笔预览相关的Canvas,不清除所有子元素
+ foreach (var canvas in VisualCanvasList.Values.ToList()) {
+ if (inkCanvas.Children.Contains(canvas)) {
+ inkCanvas.Children.Remove(canvas);
+ }
+ }
StrokeVisualList.Clear();
VisualCanvasList.Clear();
TouchDownPointsList.Clear();
@@ -446,7 +499,11 @@ namespace Ink_Canvas {
{
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
}
+ // 保存非笔画元素(如图片)
+ var preservedElements = PreserveNonStrokeElements();
inkCanvas.Children.Clear();
+ // 恢复非笔画元素
+ RestoreNonStrokeElements(preservedElements);
isInMultiTouchMode = false;
// 关闭多指书写时,恢复手掌擦开关
if (palmEraserWasEnabledBeforeMultiTouch) {
@@ -471,7 +528,11 @@ namespace Ink_Canvas {
{
inkCanvas.EditingMode = InkCanvasEditingMode.None;
}
+ // 保存非笔画元素(如图片)
+ var preservedElements = PreserveNonStrokeElements();
inkCanvas.Children.Clear();
+ // 恢复非笔画元素
+ RestoreNonStrokeElements(preservedElements);
isInMultiTouchMode = true;
// 启用多指书写时,自动禁用手掌擦
palmEraserWasEnabledBeforeMultiTouch = Settings.Canvas.EnablePalmEraser;
From b2ef8b96ef616f9a7ce8bf0e9ff1855a6443968b Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 27 Jul 2025 22:52:04 +0800
Subject: [PATCH 2/9] fix:issue #93
---
Ink Canvas/MainWindow.xaml | 6 ++++
Ink Canvas/MainWindow_cs/MW_BoardIcons.cs | 32 +++++++++++++++++++
Ink Canvas/MainWindow_cs/MW_Settings.cs | 7 ++++
Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs | 1 +
Ink Canvas/Resources/Settings.cs | 2 ++
5 files changed, 48 insertions(+)
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index eb456c64..ca788761 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -774,6 +774,12 @@
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchClearCanvasAndClearTimeMachine_Toggled" />
+
+
+
+
Date: Mon, 28 Jul 2025 00:48:50 +0800
Subject: [PATCH 3/9] fix:issue #93
---
Ink Canvas/Resources/Settings.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Ink Canvas/Resources/Settings.cs b/Ink Canvas/Resources/Settings.cs
index eb9428fb..3831f086 100644
--- a/Ink Canvas/Resources/Settings.cs
+++ b/Ink Canvas/Resources/Settings.cs
@@ -88,7 +88,7 @@ namespace Ink_Canvas
[JsonProperty("enablePalmEraser")]
public bool EnablePalmEraser { get; set; } = true;
[JsonProperty("clearCanvasAlsoClearImages")]
- public bool ClearCanvasAlsoClearImages { get; set; } = false;
+ public bool ClearCanvasAlsoClearImages { get; set; } = true;
}
public enum OptionalOperation
From 7a141822e71a21f53f4a422751648481d93a9ab8 Mon Sep 17 00:00:00 2001
From: PrefacedCorg <1876568293@qq.com>
Date: Mon, 28 Jul 2025 01:49:54 +0800
Subject: [PATCH 4/9] fix:issue #93
---
Ink Canvas/MainWindow_cs/MW_BoardControls.cs | 17 +++++++++++++++++
Ink Canvas/MainWindow_cs/MW_TimeMachine.cs | 2 +-
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_BoardControls.cs b/Ink Canvas/MainWindow_cs/MW_BoardControls.cs
index 3e03157d..d52fed64 100644
--- a/Ink Canvas/MainWindow_cs/MW_BoardControls.cs
+++ b/Ink Canvas/MainWindow_cs/MW_BoardControls.cs
@@ -29,6 +29,15 @@ namespace Ink_Canvas {
TimeMachineHistories[0] = timeMachineHistory;
timeMachine.ClearStrokeHistory();
} else {
+ // 新增:提交所有图片元素到时间机器历史记录
+ foreach (var child in inkCanvas.Children)
+ {
+ if (child is Image img)
+ {
+ timeMachine.CommitElementInsertHistory(img);
+ }
+ }
+
var timeMachineHistory = timeMachine.ExportTimeMachineHistory();
TimeMachineHistories[CurrentWhiteboardIndex] = timeMachineHistory;
timeMachine.ClearStrokeHistory();
@@ -71,6 +80,14 @@ namespace Ink_Canvas {
foreach (var item in TimeMachineHistories[0]) ApplyHistoryToCanvas(item);
} else {
timeMachine.ImportTimeMachineHistory(TimeMachineHistories[CurrentWhiteboardIndex]);
+ // 新增:通过时间机器历史恢复图片
+ foreach (var item in TimeMachineHistories[CurrentWhiteboardIndex])
+ {
+ if (item.CommitType == TimeMachineHistoryType.ElementInsert)
+ {
+ inkCanvas.Children.Add(item.InsertedElement);
+ }
+ }
foreach (var item in TimeMachineHistories[CurrentWhiteboardIndex]) ApplyHistoryToCanvas(item);
// 恢复当前页图片信息
inkCanvas.Children.Clear();
diff --git a/Ink Canvas/MainWindow_cs/MW_TimeMachine.cs b/Ink Canvas/MainWindow_cs/MW_TimeMachine.cs
index 3774ddfa..7a9346b5 100644
--- a/Ink Canvas/MainWindow_cs/MW_TimeMachine.cs
+++ b/Ink Canvas/MainWindow_cs/MW_TimeMachine.cs
@@ -130,7 +130,7 @@ namespace Ink_Canvas {
canvas.Strokes.Remove(currentStroke);
}
} else if (item.CommitType == TimeMachineHistoryType.ElementInsert) {
- if (!item.StrokeHasBeenCleared) {
+ if (item.StrokeHasBeenCleared) {
// Undo: 移除元素
if (item.InsertedElement != null && inkCanvas.Children.Contains(item.InsertedElement))
inkCanvas.Children.Remove(item.InsertedElement);
From 41409c39d5fcef025c2e6bac64bf38801377c3e1 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Sun, 27 Jul 2025 18:05:03 +0000
Subject: [PATCH 5/9] docs: update README.md
---
README.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/README.md b/README.md
index 425438b7..06ba1be2 100644
--- a/README.md
+++ b/README.md
@@ -92,6 +92,9 @@
 MKStoler1024 📖 💻 🎨 |
 Awesome Iwb 📖 |
+
+  PrefacedCorg 💻 |
+
From d03564bce95ffce4a856a597267748c465bb56aa Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Sun, 27 Jul 2025 18:05:04 +0000
Subject: [PATCH 6/9] docs: update .all-contributorsrc
---
.all-contributorsrc | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 1cbd9444..41dcfa6e 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -79,6 +79,15 @@
"contributions": [
"doc"
]
+ },
+ {
+ "login": "PrefacedCorg",
+ "name": "PrefacedCorg",
+ "avatar_url": "https://avatars.githubusercontent.com/u/129855423?v=4",
+ "profile": "https://github.com/PrefacedCorg",
+ "contributions": [
+ "code"
+ ]
}
]
}
From 5d42a8957e885cbbcfb5214e3d03890f7512170b Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Mon, 28 Jul 2025 11:15:35 +0800
Subject: [PATCH 7/9] fix:issue #93
---
Ink Canvas/MainWindow.xaml.cs | 3 +
.../MainWindow_cs/MW_ElementsControls.cs | 12 +
.../MainWindow_cs/MW_SelectionGestures.cs | 389 ++++++++++++++++++
3 files changed, 404 insertions(+)
diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs
index 3fedee0b..f0456dca 100644
--- a/Ink Canvas/MainWindow.xaml.cs
+++ b/Ink Canvas/MainWindow.xaml.cs
@@ -404,6 +404,9 @@ namespace Ink_Canvas {
// 确保开关和设置同步
ToggleSwitchNoFocusMode.IsOn = Settings.Advanced.IsNoFocusMode;
ApplyNoFocusMode();
+
+ // 初始化UIElement选择系统
+ InitializeUIElementSelection();
}
private void SystemEventsOnDisplaySettingsChanged(object sender, EventArgs e) {
diff --git a/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs b/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs
index a2dfe888..9b725971 100644
--- a/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs
+++ b/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs
@@ -5,6 +5,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
+using System.Windows.Input;
using Microsoft.Win32;
namespace Ink_Canvas
@@ -41,6 +42,10 @@ namespace Ink_Canvas
inkCanvas.Children.Add(image);
+ // 添加鼠标事件处理,使图片可以被选择
+ image.MouseDown += UIElement_MouseDown;
+ image.IsManipulationEnabled = true;
+
timeMachine.CommitElementInsertHistory(image);
}
}
@@ -72,6 +77,9 @@ namespace Ink_Canvas
int height = bitmapImage.PixelHeight;
Image image = new Image();
+ // 设置拉伸模式为Fill,支持任意比例缩放
+ image.Stretch = Stretch.Fill;
+
if (isLoaded && Settings.Canvas.IsCompressPicturesUploaded && (width > 1920 || height > 1080))
{
double scaleX = 1920.0 / width;
@@ -116,6 +124,10 @@ namespace Ink_Canvas
InkCanvas.SetTop(mediaElement, 0);
inkCanvas.Children.Add(mediaElement);
+ // 添加鼠标事件处理,使媒体元素可以被选择
+ mediaElement.MouseDown += UIElement_MouseDown;
+ mediaElement.IsManipulationEnabled = true;
+
mediaElement.LoadedBehavior = MediaState.Manual;
mediaElement.UnloadedBehavior = MediaState.Manual;
mediaElement.Loaded += async (_, args) =>
diff --git a/Ink Canvas/MainWindow_cs/MW_SelectionGestures.cs b/Ink Canvas/MainWindow_cs/MW_SelectionGestures.cs
index ea33faef..ffc84b20 100644
--- a/Ink Canvas/MainWindow_cs/MW_SelectionGestures.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SelectionGestures.cs
@@ -6,6 +6,7 @@ using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
+using System.Windows.Shapes;
using Point = System.Windows.Point;
namespace Ink_Canvas {
@@ -272,12 +273,31 @@ namespace Ink_Canvas {
if (isProgramChangeStrokeSelection) return;
if (inkCanvas.GetSelectedStrokes().Count == 0) {
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
+ // 当没有选中笔画时,检查是否有选中的UIElement
+ CheckUIElementSelection();
}
else {
GridInkCanvasSelectionCover.Visibility = Visibility.Visible;
BorderStrokeSelectionClone.Background = Brushes.Transparent;
isStrokeSelectionCloneOn = false;
updateBorderStrokeSelectionControlLocation();
+ // 当选中笔画时,取消UIElement选择
+ DeselectUIElement();
+ }
+ }
+
+ private void CheckUIElementSelection()
+ {
+ // 检查InkCanvas中的UIElement是否被选中
+ var selectedElements = inkCanvas.GetSelectedElements();
+ if (selectedElements.Count > 0)
+ {
+ var element = selectedElements[0];
+ SelectUIElement(element);
+ }
+ else
+ {
+ DeselectUIElement();
}
}
@@ -436,5 +456,374 @@ namespace Ink_Canvas {
inkCanvas.IsManipulationEnabled = true;
SetCursorBasedOnEditingMode(inkCanvas);
}
+
+ #region UIElement Selection and Resize
+
+ private UIElement selectedUIElement = null;
+ private System.Windows.Controls.Canvas resizeHandlesCanvas = null;
+ private readonly List resizeHandles = new List();
+ private bool isResizing = false;
+ private ResizeDirection currentResizeDirection = ResizeDirection.None;
+ private Point resizeStartPoint;
+ private Rect originalElementBounds;
+
+ private enum ResizeDirection
+ {
+ None,
+ TopLeft,
+ TopCenter,
+ TopRight,
+ MiddleLeft,
+ MiddleRight,
+ BottomLeft,
+ BottomCenter,
+ BottomRight
+ }
+
+ private void InitializeUIElementSelection()
+ {
+ // 创建拖拽手柄画布
+ if (resizeHandlesCanvas == null)
+ {
+ resizeHandlesCanvas = new System.Windows.Controls.Canvas
+ {
+ Background = Brushes.Transparent,
+ IsHitTestVisible = true,
+ Visibility = Visibility.Collapsed
+ };
+
+ // 将手柄画布添加到主网格中,确保它在InkCanvas之上
+ var mainGrid = inkCanvas.Parent as Grid;
+ if (mainGrid != null)
+ {
+ mainGrid.Children.Add(resizeHandlesCanvas);
+ Panel.SetZIndex(resizeHandlesCanvas, 1000); // 确保在最上层
+ }
+ }
+
+ // 创建8个拖拽手柄
+ CreateResizeHandles();
+ }
+
+ private void CreateResizeHandles()
+ {
+ resizeHandles.Clear();
+ resizeHandlesCanvas.Children.Clear();
+
+ var directions = new[]
+ {
+ ResizeDirection.TopLeft, ResizeDirection.TopCenter, ResizeDirection.TopRight,
+ ResizeDirection.MiddleLeft, ResizeDirection.MiddleRight,
+ ResizeDirection.BottomLeft, ResizeDirection.BottomCenter, ResizeDirection.BottomRight
+ };
+
+ foreach (var direction in directions)
+ {
+ var handle = new Rectangle
+ {
+ Width = 12,
+ Height = 12,
+ Fill = Brushes.White,
+ Stroke = Brushes.DodgerBlue,
+ StrokeThickness = 2,
+ Cursor = GetCursorForDirection(direction),
+ Tag = direction
+ };
+
+ handle.MouseDown += ResizeHandle_MouseDown;
+ handle.MouseMove += ResizeHandle_MouseMove;
+ handle.MouseUp += ResizeHandle_MouseUp;
+
+ resizeHandles.Add(handle);
+ resizeHandlesCanvas.Children.Add(handle);
+ }
+ }
+
+ private Cursor GetCursorForDirection(ResizeDirection direction)
+ {
+ switch (direction)
+ {
+ case ResizeDirection.TopLeft:
+ case ResizeDirection.BottomRight:
+ return Cursors.SizeNWSE;
+ case ResizeDirection.TopRight:
+ case ResizeDirection.BottomLeft:
+ return Cursors.SizeNESW;
+ case ResizeDirection.TopCenter:
+ case ResizeDirection.BottomCenter:
+ return Cursors.SizeNS;
+ case ResizeDirection.MiddleLeft:
+ case ResizeDirection.MiddleRight:
+ return Cursors.SizeWE;
+ default:
+ return Cursors.Arrow;
+ }
+ }
+
+ private void SelectUIElement(UIElement element)
+ {
+ if (selectedUIElement == element) return;
+
+ // 取消之前的选择
+ DeselectUIElement();
+
+ // 清除笔画选择
+ if (inkCanvas.GetSelectedStrokes().Count > 0)
+ {
+ isProgramChangeStrokeSelection = true;
+ inkCanvas.Select(new StrokeCollection());
+ isProgramChangeStrokeSelection = false;
+ }
+
+ selectedUIElement = element;
+
+ if (element != null)
+ {
+ // 初始化选择系统(如果还没有初始化)
+ if (resizeHandlesCanvas == null)
+ {
+ InitializeUIElementSelection();
+ }
+
+ // 显示拖拽手柄
+ ShowResizeHandles();
+ }
+ }
+
+ private void DeselectUIElement()
+ {
+ selectedUIElement = null;
+ HideResizeHandles();
+ }
+
+ private void ShowResizeHandles()
+ {
+ if (selectedUIElement == null || resizeHandlesCanvas == null) return;
+
+ var bounds = GetUIElementBounds(selectedUIElement);
+ UpdateResizeHandlesPosition(bounds);
+ resizeHandlesCanvas.Visibility = Visibility.Visible;
+ }
+
+ private void HideResizeHandles()
+ {
+ if (resizeHandlesCanvas != null)
+ {
+ resizeHandlesCanvas.Visibility = Visibility.Collapsed;
+ }
+ }
+
+ private Rect GetUIElementBounds(UIElement element)
+ {
+ var left = InkCanvas.GetLeft(element);
+ var top = InkCanvas.GetTop(element);
+
+ if (double.IsNaN(left)) left = 0;
+ if (double.IsNaN(top)) top = 0;
+
+ var width = 0.0;
+ var height = 0.0;
+
+ if (element is FrameworkElement fe)
+ {
+ width = fe.ActualWidth > 0 ? fe.ActualWidth : fe.Width;
+ height = fe.ActualHeight > 0 ? fe.ActualHeight : fe.Height;
+ }
+
+ return new Rect(left, top, width, height);
+ }
+
+ private void UpdateResizeHandlesPosition(Rect bounds)
+ {
+ if (resizeHandles.Count != 8) return;
+
+ var handleSize = 12.0;
+ var halfHandle = handleSize / 2;
+
+ // 计算手柄位置
+ var positions = new[]
+ {
+ new Point(bounds.Left - halfHandle, bounds.Top - halfHandle), // TopLeft
+ new Point(bounds.Left + bounds.Width / 2 - halfHandle, bounds.Top - halfHandle), // TopCenter
+ new Point(bounds.Right - halfHandle, bounds.Top - halfHandle), // TopRight
+ new Point(bounds.Left - halfHandle, bounds.Top + bounds.Height / 2 - halfHandle), // MiddleLeft
+ new Point(bounds.Right - halfHandle, bounds.Top + bounds.Height / 2 - halfHandle), // MiddleRight
+ new Point(bounds.Left - halfHandle, bounds.Bottom - halfHandle), // BottomLeft
+ new Point(bounds.Left + bounds.Width / 2 - halfHandle, bounds.Bottom - halfHandle), // BottomCenter
+ new Point(bounds.Right - halfHandle, bounds.Bottom - halfHandle) // BottomRight
+ };
+
+ for (int i = 0; i < resizeHandles.Count && i < positions.Length; i++)
+ {
+ System.Windows.Controls.Canvas.SetLeft(resizeHandles[i], positions[i].X);
+ System.Windows.Controls.Canvas.SetTop(resizeHandles[i], positions[i].Y);
+ }
+ }
+
+ private void ResizeHandle_MouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (selectedUIElement == null) return;
+
+ var handle = sender as Rectangle;
+ if (handle?.Tag is ResizeDirection direction)
+ {
+ isResizing = true;
+ currentResizeDirection = direction;
+ resizeStartPoint = e.GetPosition(inkCanvas);
+ originalElementBounds = GetUIElementBounds(selectedUIElement);
+
+ handle.CaptureMouse();
+ e.Handled = true;
+ }
+ }
+
+ private void ResizeHandle_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (!isResizing || selectedUIElement == null) return;
+
+ var currentPoint = e.GetPosition(inkCanvas);
+ var deltaX = currentPoint.X - resizeStartPoint.X;
+ var deltaY = currentPoint.Y - resizeStartPoint.Y;
+
+ ResizeUIElement(deltaX, deltaY);
+ e.Handled = true;
+ }
+
+ private void ResizeHandle_MouseUp(object sender, MouseButtonEventArgs e)
+ {
+ if (isResizing)
+ {
+ isResizing = false;
+ currentResizeDirection = ResizeDirection.None;
+
+ var handle = sender as Rectangle;
+ handle?.ReleaseMouseCapture();
+ e.Handled = true;
+ }
+ }
+
+ private void ResizeUIElement(double deltaX, double deltaY)
+ {
+ if (selectedUIElement == null) return;
+
+ var newBounds = originalElementBounds;
+ const double minSize = 20.0;
+
+ switch (currentResizeDirection)
+ {
+ case ResizeDirection.TopLeft:
+ var newWidth = originalElementBounds.Width - deltaX;
+ var newHeight = originalElementBounds.Height - deltaY;
+ if (newWidth >= minSize && newHeight >= minSize)
+ {
+ newBounds.X = originalElementBounds.X + deltaX;
+ newBounds.Y = originalElementBounds.Y + deltaY;
+ newBounds.Width = newWidth;
+ newBounds.Height = newHeight;
+ }
+ break;
+
+ case ResizeDirection.TopCenter:
+ var newHeightTC = originalElementBounds.Height - deltaY;
+ if (newHeightTC >= minSize)
+ {
+ newBounds.Y = originalElementBounds.Y + deltaY;
+ newBounds.Height = newHeightTC;
+ }
+ break;
+
+ case ResizeDirection.TopRight:
+ var newWidthTR = originalElementBounds.Width + deltaX;
+ var newHeightTR = originalElementBounds.Height - deltaY;
+ if (newWidthTR >= minSize && newHeightTR >= minSize)
+ {
+ newBounds.Y = originalElementBounds.Y + deltaY;
+ newBounds.Width = newWidthTR;
+ newBounds.Height = newHeightTR;
+ }
+ break;
+
+ case ResizeDirection.MiddleLeft:
+ var newWidthML = originalElementBounds.Width - deltaX;
+ if (newWidthML >= minSize)
+ {
+ newBounds.X = originalElementBounds.X + deltaX;
+ newBounds.Width = newWidthML;
+ }
+ break;
+
+ case ResizeDirection.MiddleRight:
+ var newWidthMR = originalElementBounds.Width + deltaX;
+ if (newWidthMR >= minSize)
+ {
+ newBounds.Width = newWidthMR;
+ }
+ break;
+
+ case ResizeDirection.BottomLeft:
+ var newWidthBL = originalElementBounds.Width - deltaX;
+ var newHeightBL = originalElementBounds.Height + deltaY;
+ if (newWidthBL >= minSize && newHeightBL >= minSize)
+ {
+ newBounds.X = originalElementBounds.X + deltaX;
+ newBounds.Width = newWidthBL;
+ newBounds.Height = newHeightBL;
+ }
+ break;
+
+ case ResizeDirection.BottomCenter:
+ var newHeightBC = originalElementBounds.Height + deltaY;
+ if (newHeightBC >= minSize)
+ {
+ newBounds.Height = newHeightBC;
+ }
+ break;
+
+ case ResizeDirection.BottomRight:
+ var newWidthBR = originalElementBounds.Width + deltaX;
+ var newHeightBR = originalElementBounds.Height + deltaY;
+ if (newWidthBR >= minSize && newHeightBR >= minSize)
+ {
+ newBounds.Width = newWidthBR;
+ newBounds.Height = newHeightBR;
+ }
+ break;
+ }
+
+ // 应用新的尺寸和位置
+ ApplyUIElementBounds(selectedUIElement, newBounds);
+
+ // 更新手柄位置
+ UpdateResizeHandlesPosition(newBounds);
+ }
+
+ private void ApplyUIElementBounds(UIElement element, Rect bounds)
+ {
+ InkCanvas.SetLeft(element, bounds.X);
+ InkCanvas.SetTop(element, bounds.Y);
+
+ if (element is FrameworkElement fe)
+ {
+ fe.Width = bounds.Width;
+ fe.Height = bounds.Height;
+ }
+ }
+
+ private void UIElement_MouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (inkCanvas.EditingMode == InkCanvasEditingMode.Select)
+ {
+ var element = sender as UIElement;
+ if (element != null)
+ {
+ // 切换到选择模式并选择这个元素
+ inkCanvas.Select(new UIElement[] { element });
+ SelectUIElement(element);
+ e.Handled = true;
+ }
+ }
+ }
+
+ #endregion
}
}
\ No newline at end of file
From b5d9e21f3740512cf84b4502345a6df6e406288d Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Mon, 28 Jul 2025 11:35:47 +0800
Subject: [PATCH 8/9] =?UTF-8?q?improve:=E7=94=A8=E6=88=B7=E4=BD=93?=
=?UTF-8?q?=E9=AA=8C=E5=88=86=E7=BA=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/DeviceIdentifier.cs | 428 ++++++++++++++++++++-----
Ink Canvas/MainWindow.xaml | 1 -
Ink Canvas/MainWindow.xaml.cs | 21 +-
3 files changed, 348 insertions(+), 102 deletions(-)
diff --git a/Ink Canvas/Helpers/DeviceIdentifier.cs b/Ink Canvas/Helpers/DeviceIdentifier.cs
index e1040389..5802522c 100644
--- a/Ink Canvas/Helpers/DeviceIdentifier.cs
+++ b/Ink Canvas/Helpers/DeviceIdentifier.cs
@@ -447,7 +447,7 @@ namespace Ink_Canvas.Helpers
}
///
- /// 使用频率统计数据结构
+ /// 使用频率统计数据结构(优化至秒级精度)
///
private class UsageStats
{
@@ -460,10 +460,20 @@ namespace Ink_Canvas.Helpers
[JsonProperty("launchCount")]
public int LaunchCount { get; set; }
+ // 新的秒级精度字段
+ [JsonProperty("totalUsageSeconds")]
+ public long TotalUsageSeconds { get; set; }
+
+ [JsonProperty("averageSessionSeconds")]
+ public double AverageSessionSeconds { get; set; }
+
+ // 保留旧字段以保持向后兼容性(已弃用)
[JsonProperty("totalUsageMinutes")]
+ [Obsolete("已弃用,请使用 TotalUsageSeconds")]
public long TotalUsageMinutes { get; set; }
[JsonProperty("averageSessionMinutes")]
+ [Obsolete("已弃用,请使用 AverageSessionSeconds")]
public double AverageSessionMinutes { get; set; }
[JsonProperty("lastUpdateCheck")]
@@ -481,12 +491,12 @@ namespace Ink_Canvas.Helpers
[JsonProperty("lastModified")]
public DateTime LastModified { get; set; }
- // 每周统计数据
+ // 每周统计数据(秒级精度)
[JsonProperty("weeklyLaunchCount")]
public int WeeklyLaunchCount { get; set; }
- [JsonProperty("weeklyUsageMinutes")]
- public long WeeklyUsageMinutes { get; set; }
+ [JsonProperty("weeklyUsageSeconds")]
+ public long WeeklyUsageSeconds { get; set; }
[JsonProperty("weekStartDate")]
public DateTime WeekStartDate { get; set; }
@@ -494,11 +504,58 @@ namespace Ink_Canvas.Helpers
[JsonProperty("lastWeekLaunchCount")]
public int LastWeekLaunchCount { get; set; }
+ [JsonProperty("lastWeekUsageSeconds")]
+ public long LastWeekUsageSeconds { get; set; }
+
+ // 保留旧字段以保持向后兼容性(已弃用)
+ [JsonProperty("weeklyUsageMinutes")]
+ [Obsolete("已弃用,请使用 WeeklyUsageSeconds")]
+ public long WeeklyUsageMinutes { get; set; }
+
[JsonProperty("lastWeekUsageMinutes")]
+ [Obsolete("已弃用,请使用 LastWeekUsageSeconds")]
public long LastWeekUsageMinutes { get; set; }
///
- /// 检查并重置每周统计数据
+ /// 数据迁移:从分钟精度迁移到秒级精度
+ ///
+ public void MigrateToSecondsPrecision()
+ {
+ try
+ {
+ // 如果新字段为空但旧字段有数据,进行迁移
+ if (TotalUsageSeconds == 0 && TotalUsageMinutes > 0)
+ {
+ TotalUsageSeconds = TotalUsageMinutes * 60;
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 迁移总使用时长: {TotalUsageMinutes}分钟 -> {TotalUsageSeconds}秒");
+ }
+
+ if (AverageSessionSeconds == 0 && AverageSessionMinutes > 0)
+ {
+ AverageSessionSeconds = AverageSessionMinutes * 60;
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 迁移平均会话时长: {AverageSessionMinutes}分钟 -> {AverageSessionSeconds}秒");
+ }
+
+ if (WeeklyUsageSeconds == 0 && WeeklyUsageMinutes > 0)
+ {
+ WeeklyUsageSeconds = WeeklyUsageMinutes * 60;
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 迁移每周使用时长: {WeeklyUsageMinutes}分钟 -> {WeeklyUsageSeconds}秒");
+ }
+
+ if (LastWeekUsageSeconds == 0 && LastWeekUsageMinutes > 0)
+ {
+ LastWeekUsageSeconds = LastWeekUsageMinutes * 60;
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 迁移上周使用时长: {LastWeekUsageMinutes}分钟 -> {LastWeekUsageSeconds}秒");
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 数据迁移失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 检查并重置每周统计数据(秒级精度)
///
public void CheckAndResetWeeklyStats()
{
@@ -510,14 +567,18 @@ namespace Ink_Canvas.Helpers
{
// 保存上周数据
LastWeekLaunchCount = WeeklyLaunchCount;
- LastWeekUsageMinutes = WeeklyUsageMinutes;
+ LastWeekUsageSeconds = WeeklyUsageSeconds;
+
+ // 同时更新旧字段以保持兼容性
+ LastWeekUsageMinutes = LastWeekUsageSeconds / 60;
// 重置本周数据
WeeklyLaunchCount = 0;
+ WeeklyUsageSeconds = 0;
WeeklyUsageMinutes = 0;
WeekStartDate = currentWeekStart;
- LogHelper.WriteLogToFile($"DeviceIdentifier | 每周统计重置 - 上周启动: {LastWeekLaunchCount}次, 上周使用: {LastWeekUsageMinutes}分钟");
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 每周统计重置 - 上周启动: {LastWeekLaunchCount}次, 上周使用: {FormatDuration(LastWeekUsageSeconds)}");
}
}
@@ -541,20 +602,25 @@ namespace Ink_Canvas.Helpers
}
///
- /// 记录本周的使用时长
+ /// 记录本周的使用时长(秒级精度)
///
- public void RecordWeeklyUsage(long minutes)
+ public void RecordWeeklyUsage(long seconds)
{
CheckAndResetWeeklyStats();
- WeeklyUsageMinutes += minutes;
+ WeeklyUsageSeconds += seconds;
+ // 同时更新旧字段以保持兼容性
+ WeeklyUsageMinutes = WeeklyUsageSeconds / 60;
}
+
+
///
- /// 计算数据哈希值用于完整性验证
+ /// 计算数据哈希值用于完整性验证(秒级精度)
///
public void UpdateDataHash()
{
- var dataString = $"{DeviceId}|{LaunchCount}|{TotalUsageMinutes}|{LastLaunchTime:yyyyMMddHHmmss}|{WeeklyLaunchCount}|{WeeklyUsageMinutes}|{DataIntegrityKey}";
+ // 使用秒级精度数据计算哈希
+ var dataString = $"{DeviceId}|{LaunchCount}|{TotalUsageSeconds}|{LastLaunchTime:yyyyMMddHHmmss}|{WeeklyLaunchCount}|{WeeklyUsageSeconds}|{DataIntegrityKey}";
using (var sha256 = SHA256.Create())
{
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(dataString));
@@ -564,17 +630,30 @@ namespace Ink_Canvas.Helpers
}
///
- /// 验证数据完整性
+ /// 验证数据完整性(秒级精度)
///
public bool VerifyDataIntegrity()
{
try
{
- var dataString = $"{DeviceId}|{LaunchCount}|{TotalUsageMinutes}|{LastLaunchTime:yyyyMMddHHmmss}|{WeeklyLaunchCount}|{WeeklyUsageMinutes}|{DataIntegrityKey}";
+ // 首先尝试使用秒级精度验证
+ var dataString = $"{DeviceId}|{LaunchCount}|{TotalUsageSeconds}|{LastLaunchTime:yyyyMMddHHmmss}|{WeeklyLaunchCount}|{WeeklyUsageSeconds}|{DataIntegrityKey}";
using (var sha256 = SHA256.Create())
{
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(dataString));
var expectedHash = Convert.ToBase64String(hashBytes);
+ if (DataHash == expectedHash)
+ {
+ return true;
+ }
+ }
+
+ // 如果秒级精度验证失败,尝试使用旧的分钟精度验证(向后兼容)
+ var oldDataString = $"{DeviceId}|{LaunchCount}|{TotalUsageMinutes}|{LastLaunchTime:yyyyMMddHHmmss}|{WeeklyLaunchCount}|{WeeklyUsageMinutes}|{DataIntegrityKey}";
+ using (var sha256 = SHA256.Create())
+ {
+ var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(oldDataString));
+ var expectedHash = Convert.ToBase64String(hashBytes);
return DataHash == expectedHash;
}
}
@@ -585,6 +664,37 @@ namespace Ink_Canvas.Helpers
}
}
+ ///
+ /// 格式化时长显示(秒级精度)
+ ///
+ /// 总秒数
+ /// 格式化的时长字符串
+ public static string FormatDuration(long totalSeconds)
+ {
+ if (totalSeconds < 60)
+ {
+ return $"{totalSeconds}秒";
+ }
+ else if (totalSeconds < 3600)
+ {
+ var minutes = totalSeconds / 60;
+ var seconds = totalSeconds % 60;
+ return seconds > 0 ? $"{minutes}分{seconds}秒" : $"{minutes}分钟";
+ }
+ else
+ {
+ var hours = totalSeconds / 3600;
+ var minutes = (totalSeconds % 3600) / 60;
+ var seconds = totalSeconds % 60;
+
+ var result = $"{hours}小时";
+ if (minutes > 0) result += $"{minutes}分";
+ if (seconds > 0) result += $"{seconds}秒";
+
+ return result;
+ }
+ }
+
///
/// 更新推送优先级枚举
///
@@ -640,7 +750,7 @@ namespace Ink_Canvas.Helpers
}
///
- /// 记录应用退出(计算使用时长)
+ /// 记录应用退出(计算使用时长 - 秒级精度)
///
public static void RecordAppExit()
{
@@ -650,21 +760,31 @@ namespace Ink_Canvas.Helpers
{
var stats = LoadUsageStats();
- // 计算本次会话时长
- long sessionMinutes = 0;
+ // 执行数据迁移(如果需要)
+ stats.MigrateToSecondsPrecision();
+
+ // 计算本次会话时长(秒级精度)
+ long sessionSeconds = 0;
if (stats.LastLaunchTime != DateTime.MinValue)
{
var sessionDuration = DateTime.Now - stats.LastLaunchTime;
- sessionMinutes = (long)sessionDuration.TotalMinutes;
- stats.TotalUsageMinutes += sessionMinutes;
+ sessionSeconds = (long)sessionDuration.TotalSeconds;
- // 记录每周使用时长
- stats.RecordWeeklyUsage(sessionMinutes);
+ // 更新秒级精度数据
+ stats.TotalUsageSeconds += sessionSeconds;
- // 更新平均会话时长
+ // 同时更新旧字段以保持兼容性
+ stats.TotalUsageMinutes = stats.TotalUsageSeconds / 60;
+
+ // 记录每周使用时长(秒级精度)
+ stats.RecordWeeklyUsage(sessionSeconds);
+
+ // 更新平均会话时长(秒级精度)
if (stats.LaunchCount > 0)
{
- stats.AverageSessionMinutes = (double)stats.TotalUsageMinutes / stats.LaunchCount;
+ stats.AverageSessionSeconds = (double)stats.TotalUsageSeconds / stats.LaunchCount;
+ // 同时更新旧字段以保持兼容性
+ stats.AverageSessionMinutes = stats.AverageSessionSeconds / 60;
}
}
@@ -676,7 +796,9 @@ namespace Ink_Canvas.Helpers
SaveUsageStats(stats);
- LogHelper.WriteLogToFile($"DeviceIdentifier | 记录应用退出 - 本次会话: {sessionMinutes}分钟, 总时长: {stats.TotalUsageMinutes}分钟, 本周时长: {stats.WeeklyUsageMinutes}分钟");
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 记录应用退出 - 本次会话: {FormatDuration(sessionSeconds)}, " +
+ $"总时长: {FormatDuration(stats.TotalUsageSeconds)}, " +
+ $"本周时长: {FormatDuration(stats.WeeklyUsageSeconds)}");
}
}
catch (Exception ex)
@@ -699,16 +821,28 @@ namespace Ink_Canvas.Helpers
// 计算最近活跃度
var daysSinceLastUse = (DateTime.Now - stats.LastLaunchTime).TotalDays;
- // 使用真实的每周数据
+ // 使用真实的每周数据(秒级精度)
var currentWeekLaunches = stats.WeeklyLaunchCount;
- var currentWeekMinutes = stats.WeeklyUsageMinutes;
+ var currentWeekSeconds = stats.WeeklyUsageSeconds;
+
+ // 如果秒级数据为空但分钟数据存在,进行转换
+ if (currentWeekSeconds == 0 && stats.WeeklyUsageMinutes > 0)
+ {
+ currentWeekSeconds = stats.WeeklyUsageMinutes * 60;
+ }
// 如果本周数据不足,参考上周数据
var weeklyLaunches = currentWeekLaunches > 0 ? currentWeekLaunches : stats.LastWeekLaunchCount;
- var weeklyMinutes = currentWeekMinutes > 0 ? currentWeekMinutes : stats.LastWeekUsageMinutes;
+ var weeklySeconds = currentWeekSeconds > 0 ? currentWeekSeconds : stats.LastWeekUsageSeconds;
+
+ // 如果秒级数据仍为空,使用分钟数据转换
+ if (weeklySeconds == 0 && stats.LastWeekUsageMinutes > 0)
+ {
+ weeklySeconds = stats.LastWeekUsageMinutes * 60;
+ }
// 综合评分系统(0-100分)
- var frequencyScore = CalculateFrequencyScoreWithWeeklyData(stats, daysSinceLastUse, weeklyLaunches, weeklyMinutes);
+ var frequencyScore = CalculateFrequencyScoreWithWeeklyData(stats, daysSinceLastUse, weeklyLaunches, weeklySeconds);
// 根据综合评分确定频率分类和更新优先级
if (frequencyScore >= 80)
@@ -728,7 +862,7 @@ namespace Ink_Canvas.Helpers
}
LogHelper.WriteLogToFile($"DeviceIdentifier | 使用频率计算 - 评分: {frequencyScore}, 频率: {stats.UsageFrequency}, " +
- $"优先级: {stats.UpdatePriority}, 本周启动: {currentWeekLaunches}次, 本周时长: {currentWeekMinutes}分钟");
+ $"优先级: {stats.UpdatePriority}, 本周启动: {currentWeekLaunches}次, 本周时长: {FormatDuration(currentWeekSeconds)}");
}
catch (Exception ex)
{
@@ -740,16 +874,16 @@ namespace Ink_Canvas.Helpers
}
///
- /// 基于每周真实数据计算综合频率评分(0-100分)
+ /// 基于每周真实数据计算综合频率评分(0-100分,秒级精度)
/// 评分标准:≥80分=高频用户,40-79分=中频用户,<40分=低频用户
///
/// 使用统计数据
/// 距离最后使用的天数
/// 每周启动次数
- /// 每周使用时长
+ /// 每周使用时长(秒)
/// 综合评分(0-100分)
private static int CalculateFrequencyScoreWithWeeklyData(UsageStats stats, double daysSinceLastUse,
- long weeklyLaunches, long weeklyMinutes)
+ long weeklyLaunches, long weeklySeconds)
{
var score = 0;
@@ -766,16 +900,17 @@ namespace Ink_Canvas.Helpers
else if (weeklyLaunches >= 3) score += 15; // 3-4次:中频使用
else if (weeklyLaunches >= 1) score += 10; // 1-2次:低频使用
- // 每周使用时长评分(20分)- 基于真实的每周使用时长
- if (weeklyMinutes >= 600) score += 20; // 10小时以上:重度使用
- else if (weeklyMinutes >= 300) score += 15; // 5-10小时:中重度使用
- else if (weeklyMinutes >= 120) score += 10; // 2-5小时:中度使用
- else if (weeklyMinutes >= 60) score += 5; // 1-2小时:轻度使用
+ // 每周使用时长评分(20分)- 基于真实的每周使用时长(秒级精度)
+ if (weeklySeconds >= 36000) score += 20; // 10小时以上:重度使用
+ else if (weeklySeconds >= 18000) score += 15; // 5-10小时:中重度使用
+ else if (weeklySeconds >= 7200) score += 10; // 2-5小时:中度使用
+ else if (weeklySeconds >= 3600) score += 5; // 1-2小时:轻度使用
- // 历史使用深度评分(10分)- 反映用户的长期使用习惯
- if (stats.TotalUsageMinutes >= 3000) score += 10; // 50小时以上:资深用户
- else if (stats.TotalUsageMinutes >= 1200) score += 7; // 20-50小时:中等用户
- else if (stats.TotalUsageMinutes >= 300) score += 4; // 5-20小时:新手用户
+ // 历史使用深度评分(10分)- 反映用户的长期使用习惯(秒级精度)
+ var totalSeconds = stats.TotalUsageSeconds > 0 ? stats.TotalUsageSeconds : stats.TotalUsageMinutes * 60;
+ if (totalSeconds >= 180000) score += 10; // 50小时以上:资深用户
+ else if (totalSeconds >= 72000) score += 7; // 20-50小时:中等用户
+ else if (totalSeconds >= 18000) score += 4; // 5-20小时:新手用户
return Math.Min(100, score);
}
@@ -817,14 +952,14 @@ namespace Ink_Canvas.Helpers
}
///
- /// 获取使用统计信息
+ /// 获取使用统计信息(秒级精度)
///
- public static (int launchCount, long totalMinutes, double avgSession, UpdatePriority priority) GetUsageStats()
+ public static (int launchCount, long totalSeconds, double avgSessionSeconds, UpdatePriority priority) GetUsageStats()
{
try
{
var stats = LoadUsageStats();
- return (stats.LaunchCount, stats.TotalUsageMinutes, stats.AverageSessionMinutes, stats.UpdatePriority);
+ return (stats.LaunchCount, stats.TotalUsageSeconds, stats.AverageSessionSeconds, stats.UpdatePriority);
}
catch (Exception ex)
{
@@ -834,7 +969,27 @@ namespace Ink_Canvas.Helpers
}
///
- /// 加载使用统计 - 支持多重备份恢复和智能反篡改(强化版本)
+ /// 获取使用统计信息(兼容性方法 - 分钟精度)
+ ///
+ [Obsolete("请使用 GetUsageStats() 获取秒级精度数据")]
+ public static (int launchCount, long totalMinutes, double avgSessionMinutes, UpdatePriority priority) GetUsageStatsInMinutes()
+ {
+ try
+ {
+ var stats = LoadUsageStats();
+ var totalMinutes = stats.TotalUsageSeconds / 60;
+ var avgMinutes = stats.AverageSessionSeconds / 60;
+ return (stats.LaunchCount, totalMinutes, avgMinutes, stats.UpdatePriority);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 获取使用统计失败: {ex.Message}", LogHelper.LogType.Error);
+ return (0, 0, 0, UpdatePriority.Medium);
+ }
+ }
+
+ ///
+ /// 加载使用统计 - 支持多重备份恢复和智能反篡改
///
private static UsageStats LoadUsageStats()
{
@@ -851,6 +1006,9 @@ namespace Ink_Canvas.Helpers
{
LogHelper.WriteLogToFile($"DeviceIdentifier | 使用最可信数据源恢复使用统计: {bestData.Source}");
+ // 执行数据迁移(如果需要)
+ bestData.Stats.MigrateToSecondsPrecision();
+
// 确保备份同步
SaveUsageStatsToAllLocations(bestData.Stats);
return bestData.Stats;
@@ -864,6 +1022,10 @@ namespace Ink_Canvas.Helpers
if (partiallyRecoveredData != null)
{
LogHelper.WriteLogToFile($"DeviceIdentifier | 从部分损坏数据中恢复使用统计");
+
+ // 执行数据迁移(如果需要)
+ partiallyRecoveredData.MigrateToSecondsPrecision();
+
SaveUsageStatsToAllLocations(partiallyRecoveredData);
return partiallyRecoveredData;
}
@@ -873,14 +1035,16 @@ namespace Ink_Canvas.Helpers
LogHelper.WriteLogToFile($"DeviceIdentifier | 加载使用统计失败: {ex.Message}", LogHelper.LogType.Error);
}
- // 返回新的统计对象
+ // 返回新的统计对象(秒级精度)
var newStats = new UsageStats
{
DeviceId = DeviceId,
LastLaunchTime = DateTime.Now,
LaunchCount = 0,
- TotalUsageMinutes = 0,
- AverageSessionMinutes = 0,
+ TotalUsageSeconds = 0,
+ AverageSessionSeconds = 0,
+ TotalUsageMinutes = 0, // 保持兼容性
+ AverageSessionMinutes = 0, // 保持兼容性
LastUpdateCheck = DateTime.MinValue,
UpdatePriority = UpdatePriority.Medium,
UsageFrequency = UsageFrequency.Medium
@@ -1129,8 +1293,9 @@ namespace Ink_Canvas.Helpers
UsageFrequency = UsageFrequency.Medium
};
- // 使用多数投票或最大值策略恢复关键数据
+ // 使用多数投票或最大值策略恢复关键数据(秒级精度)
var launchCounts = dataSources.Where(d => d.Stats.LaunchCount > 0).Select(d => d.Stats.LaunchCount).ToList();
+ var usageSeconds = dataSources.Where(d => d.Stats.TotalUsageSeconds > 0).Select(d => d.Stats.TotalUsageSeconds).ToList();
var usageMinutes = dataSources.Where(d => d.Stats.TotalUsageMinutes > 0).Select(d => d.Stats.TotalUsageMinutes).ToList();
if (launchCounts.Count > 0)
@@ -1138,15 +1303,23 @@ namespace Ink_Canvas.Helpers
recoveredStats.LaunchCount = (int)launchCounts.Average(); // 使用平均值
}
- if (usageMinutes.Count > 0)
+ // 优先使用秒级数据,如果没有则使用分钟数据转换
+ if (usageSeconds.Count > 0)
+ {
+ recoveredStats.TotalUsageSeconds = (long)usageSeconds.Average(); // 使用平均值
+ recoveredStats.TotalUsageMinutes = recoveredStats.TotalUsageSeconds / 60; // 兼容性
+ }
+ else if (usageMinutes.Count > 0)
{
recoveredStats.TotalUsageMinutes = (long)usageMinutes.Average(); // 使用平均值
+ recoveredStats.TotalUsageSeconds = recoveredStats.TotalUsageMinutes * 60; // 转换为秒
}
- // 重新计算平均会话时长
+ // 重新计算平均会话时长(秒级精度)
if (recoveredStats.LaunchCount > 0)
{
- recoveredStats.AverageSessionMinutes = (double)recoveredStats.TotalUsageMinutes / recoveredStats.LaunchCount;
+ recoveredStats.AverageSessionSeconds = (double)recoveredStats.TotalUsageSeconds / recoveredStats.LaunchCount;
+ recoveredStats.AverageSessionMinutes = recoveredStats.AverageSessionSeconds / 60; // 兼容性
}
// 重新计算使用频率
@@ -1155,7 +1328,7 @@ namespace Ink_Canvas.Helpers
// 更新数据完整性哈希
recoveredStats.UpdateDataHash();
- LogHelper.WriteLogToFile($"DeviceIdentifier | 部分数据恢复完成 - 启动次数: {recoveredStats.LaunchCount}, 使用时长: {recoveredStats.TotalUsageMinutes}分钟");
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 部分数据恢复完成 - 启动次数: {recoveredStats.LaunchCount}, 使用时长: {FormatDuration(recoveredStats.TotalUsageSeconds)}");
return recoveredStats;
}
catch (Exception ex)
@@ -1178,19 +1351,32 @@ namespace Ink_Canvas.Helpers
{
var deviceId = key.GetValue("DeviceId") as string;
var launchCount = key.GetValue("LaunchCount");
+
+ // 秒级精度数据
+ var totalSeconds = key.GetValue("TotalUsageSeconds");
+ var avgSessionSeconds = key.GetValue("AverageSessionSeconds");
+
+ // 兼容性:分钟精度数据
var totalMinutes = key.GetValue("TotalUsageMinutes");
+ var avgSessionMinutes = key.GetValue("AverageSessionMinutes");
+
var lastLaunch = key.GetValue("LastLaunchTime") as string;
var priority = key.GetValue("UpdatePriority");
var frequency = key.GetValue("UsageFrequency");
var dataHash = key.GetValue("DataHash") as string;
var lastUpdate = key.GetValue("LastUpdate") as string;
- // 每周统计数据
+ // 每周统计数据(秒级精度)
var weeklyLaunchCount = key.GetValue("WeeklyLaunchCount");
+ var weeklyUsageSeconds = key.GetValue("WeeklyUsageSeconds");
+ var lastWeekUsageSeconds = key.GetValue("LastWeekUsageSeconds");
+
+ // 兼容性:分钟精度数据
var weeklyUsageMinutes = key.GetValue("WeeklyUsageMinutes");
+ var lastWeekUsageMinutes = key.GetValue("LastWeekUsageMinutes");
+
var weekStartDate = key.GetValue("WeekStartDate") as string;
var lastWeekLaunchCount = key.GetValue("LastWeekLaunchCount");
- var lastWeekUsageMinutes = key.GetValue("LastWeekUsageMinutes");
if (!string.IsNullOrEmpty(deviceId) && launchCount != null)
{
@@ -1198,26 +1384,42 @@ namespace Ink_Canvas.Helpers
{
DeviceId = deviceId,
LaunchCount = Convert.ToInt32(launchCount),
+
+ // 秒级精度数据
+ TotalUsageSeconds = totalSeconds != null ? Convert.ToInt64(totalSeconds) : 0,
+ AverageSessionSeconds = avgSessionSeconds != null ? Convert.ToDouble(avgSessionSeconds) : 0,
+
+ // 兼容性:分钟精度数据
TotalUsageMinutes = totalMinutes != null ? Convert.ToInt64(totalMinutes) : 0,
+ AverageSessionMinutes = avgSessionMinutes != null ? Convert.ToDouble(avgSessionMinutes) : 0,
+
LastLaunchTime = DateTime.TryParse(lastLaunch, out var dt) ? dt : DateTime.Now,
UpdatePriority = priority != null ? (UpdatePriority)Convert.ToInt32(priority) : UpdatePriority.Medium,
UsageFrequency = frequency != null ? (UsageFrequency)Convert.ToInt32(frequency) : UsageFrequency.Medium,
DataHash = dataHash,
- AverageSessionMinutes = 0,
LastUpdateCheck = DateTime.MinValue,
- // 每周统计数据
+ // 每周统计数据(秒级精度)
WeeklyLaunchCount = weeklyLaunchCount != null ? Convert.ToInt32(weeklyLaunchCount) : 0,
+ WeeklyUsageSeconds = weeklyUsageSeconds != null ? Convert.ToInt64(weeklyUsageSeconds) : 0,
+ LastWeekUsageSeconds = lastWeekUsageSeconds != null ? Convert.ToInt64(lastWeekUsageSeconds) : 0,
+
+ // 兼容性:分钟精度数据
WeeklyUsageMinutes = weeklyUsageMinutes != null ? Convert.ToInt64(weeklyUsageMinutes) : 0,
+ LastWeekUsageMinutes = lastWeekUsageMinutes != null ? Convert.ToInt64(lastWeekUsageMinutes) : 0,
+
WeekStartDate = DateTime.TryParse(weekStartDate, out var wsd) ? wsd : DateTime.MinValue,
- LastWeekLaunchCount = lastWeekLaunchCount != null ? Convert.ToInt32(lastWeekLaunchCount) : 0,
- LastWeekUsageMinutes = lastWeekUsageMinutes != null ? Convert.ToInt64(lastWeekUsageMinutes) : 0
+ LastWeekLaunchCount = lastWeekLaunchCount != null ? Convert.ToInt32(lastWeekLaunchCount) : 0
};
+ // 执行数据迁移(如果需要)
+ stats.MigrateToSecondsPrecision();
+
// 重新计算平均会话时长
- if (stats.LaunchCount > 0)
+ if (stats.LaunchCount > 0 && stats.AverageSessionSeconds == 0)
{
- stats.AverageSessionMinutes = (double)stats.TotalUsageMinutes / stats.LaunchCount;
+ stats.AverageSessionSeconds = (double)stats.TotalUsageSeconds / stats.LaunchCount;
+ stats.AverageSessionMinutes = stats.AverageSessionSeconds / 60;
}
var dataSource = new DataSourceInfo
@@ -1260,46 +1462,75 @@ namespace Ink_Canvas.Helpers
if (key != null)
{
var launchCount = key.GetValue("LC");
+
+ // 秒级精度数据
+ var totalSeconds = key.GetValue("TUS");
+ var avgSessionSeconds = key.GetValue("ASS");
+
+ // 兼容性:分钟精度数据
var totalMinutes = key.GetValue("TUM");
+ var avgSessionMinutes = key.GetValue("ASM");
+
var lastLaunchBinary = key.GetValue("LLT");
var priority = key.GetValue("UP");
var frequency = key.GetValue("UF");
var dataHash = key.GetValue("DH") as string;
var lastUpdateBinary = key.GetValue("LU");
- // 每周统计数据
+ // 每周统计数据(秒级精度)
var weeklyLaunchCount = key.GetValue("WLC");
+ var weeklyUsageSeconds = key.GetValue("WUS");
+ var lastWeekUsageSeconds = key.GetValue("LWUS");
+
+ // 兼容性:分钟精度数据
var weeklyUsageMinutes = key.GetValue("WUM");
- var weekStartDateBinary = key.GetValue("WSD");
- var lastWeekLaunchCount = key.GetValue("LWLC");
var lastWeekUsageMinutes = key.GetValue("LWUM");
- if (launchCount != null && totalMinutes != null)
+ var weekStartDateBinary = key.GetValue("WSD");
+ var lastWeekLaunchCount = key.GetValue("LWLC");
+
+ if (launchCount != null && (totalSeconds != null || totalMinutes != null))
{
var stats = new UsageStats
{
DeviceId = DeviceId,
LaunchCount = Convert.ToInt32(launchCount),
- TotalUsageMinutes = Convert.ToInt64(totalMinutes),
+
+ // 秒级精度数据
+ TotalUsageSeconds = totalSeconds != null ? Convert.ToInt64(totalSeconds) : 0,
+ AverageSessionSeconds = avgSessionSeconds != null ? Convert.ToDouble(avgSessionSeconds) : 0,
+
+ // 兼容性:分钟精度数据
+ TotalUsageMinutes = totalMinutes != null ? Convert.ToInt64(totalMinutes) : 0,
+ AverageSessionMinutes = avgSessionMinutes != null ? Convert.ToDouble(avgSessionMinutes) : 0,
+
LastLaunchTime = lastLaunchBinary != null ? DateTime.FromBinary(Convert.ToInt64(lastLaunchBinary)) : DateTime.Now,
UpdatePriority = priority != null ? (UpdatePriority)Convert.ToInt32(priority) : UpdatePriority.Medium,
UsageFrequency = frequency != null ? (UsageFrequency)Convert.ToInt32(frequency) : UsageFrequency.Medium,
DataHash = dataHash,
- AverageSessionMinutes = 0,
LastUpdateCheck = DateTime.MinValue,
- // 每周统计数据
+ // 每周统计数据(秒级精度)
WeeklyLaunchCount = weeklyLaunchCount != null ? Convert.ToInt32(weeklyLaunchCount) : 0,
+ WeeklyUsageSeconds = weeklyUsageSeconds != null ? Convert.ToInt64(weeklyUsageSeconds) : 0,
+ LastWeekUsageSeconds = lastWeekUsageSeconds != null ? Convert.ToInt64(lastWeekUsageSeconds) : 0,
+
+ // 兼容性:分钟精度数据
WeeklyUsageMinutes = weeklyUsageMinutes != null ? Convert.ToInt64(weeklyUsageMinutes) : 0,
+ LastWeekUsageMinutes = lastWeekUsageMinutes != null ? Convert.ToInt64(lastWeekUsageMinutes) : 0,
+
WeekStartDate = weekStartDateBinary != null ? DateTime.FromBinary(Convert.ToInt64(weekStartDateBinary)) : DateTime.MinValue,
- LastWeekLaunchCount = lastWeekLaunchCount != null ? Convert.ToInt32(lastWeekLaunchCount) : 0,
- LastWeekUsageMinutes = lastWeekUsageMinutes != null ? Convert.ToInt64(lastWeekUsageMinutes) : 0
+ LastWeekLaunchCount = lastWeekLaunchCount != null ? Convert.ToInt32(lastWeekLaunchCount) : 0
};
+ // 执行数据迁移(如果需要)
+ stats.MigrateToSecondsPrecision();
+
// 重新计算平均会话时长
- if (stats.LaunchCount > 0)
+ if (stats.LaunchCount > 0 && stats.AverageSessionSeconds == 0)
{
- stats.AverageSessionMinutes = (double)stats.TotalUsageMinutes / stats.LaunchCount;
+ stats.AverageSessionSeconds = (double)stats.TotalUsageSeconds / stats.LaunchCount;
+ stats.AverageSessionMinutes = stats.AverageSessionSeconds / 60;
}
var dataSource = new DataSourceInfo
@@ -1497,21 +1728,35 @@ namespace Ink_Canvas.Helpers
{
key.SetValue("DeviceId", stats.DeviceId);
key.SetValue("LaunchCount", stats.LaunchCount);
+
+ // 秒级精度数据
+ key.SetValue("TotalUsageSeconds", stats.TotalUsageSeconds);
+ key.SetValue("AverageSessionSeconds", stats.AverageSessionSeconds);
+
+ // 兼容性:分钟精度数据
key.SetValue("TotalUsageMinutes", stats.TotalUsageMinutes);
+ key.SetValue("AverageSessionMinutes", stats.AverageSessionMinutes);
+
key.SetValue("LastLaunchTime", stats.LastLaunchTime.ToString("yyyy-MM-dd HH:mm:ss"));
key.SetValue("UpdatePriority", (int)stats.UpdatePriority);
key.SetValue("UsageFrequency", (int)stats.UsageFrequency);
key.SetValue("DataHash", stats.DataHash ?? "");
key.SetValue("LastUpdate", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
- // 每周统计数据
+ // 每周统计数据(秒级精度)
key.SetValue("WeeklyLaunchCount", stats.WeeklyLaunchCount);
+ key.SetValue("WeeklyUsageSeconds", stats.WeeklyUsageSeconds);
+ key.SetValue("LastWeekUsageSeconds", stats.LastWeekUsageSeconds);
+
+ // 兼容性:分钟精度数据
key.SetValue("WeeklyUsageMinutes", stats.WeeklyUsageMinutes);
- key.SetValue("WeekStartDate", stats.WeekStartDate.ToString("yyyy-MM-dd"));
- key.SetValue("LastWeekLaunchCount", stats.LastWeekLaunchCount);
key.SetValue("LastWeekUsageMinutes", stats.LastWeekUsageMinutes);
- LogHelper.WriteLogToFile($"DeviceIdentifier | 使用统计已保存到主注册表 - 总启动: {stats.LaunchCount}次, 本周启动: {stats.WeeklyLaunchCount}次, 总时长: {stats.TotalUsageMinutes}分钟, 本周时长: {stats.WeeklyUsageMinutes}分钟");
+ key.SetValue("WeekStartDate", stats.WeekStartDate.ToString("yyyy-MM-dd"));
+ key.SetValue("LastWeekLaunchCount", stats.LastWeekLaunchCount);
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 使用统计已保存到主注册表 - 总启动: {stats.LaunchCount}次, 本周启动: {stats.WeeklyLaunchCount}次, " +
+ $"总时长: {FormatDuration(stats.TotalUsageSeconds)}, 本周时长: {FormatDuration(stats.WeeklyUsageSeconds)}");
}
else
{
@@ -1548,21 +1793,34 @@ namespace Ink_Canvas.Helpers
{
if (key != null)
{
- // 使用编码的键名来隐藏数据
+ // 使用编码的键名来隐藏数据(秒级精度)
key.SetValue("LC", stats.LaunchCount); // LaunchCount
+
+ // 秒级精度数据
+ key.SetValue("TUS", stats.TotalUsageSeconds); // TotalUsageSeconds
+ key.SetValue("ASS", stats.AverageSessionSeconds); // AverageSessionSeconds
+
+ // 兼容性:分钟精度数据
key.SetValue("TUM", stats.TotalUsageMinutes); // TotalUsageMinutes
+ key.SetValue("ASM", stats.AverageSessionMinutes); // AverageSessionMinutes
+
key.SetValue("LLT", stats.LastLaunchTime.ToBinary()); // LastLaunchTime
key.SetValue("UP", (int)stats.UpdatePriority); // UpdatePriority
key.SetValue("UF", (int)stats.UsageFrequency); // UsageFrequency
key.SetValue("DH", stats.DataHash ?? ""); // DataHash
key.SetValue("LU", DateTime.Now.ToBinary()); // LastUpdate
- // 每周统计数据
+ // 每周统计数据(秒级精度)
key.SetValue("WLC", stats.WeeklyLaunchCount); // WeeklyLaunchCount
+ key.SetValue("WUS", stats.WeeklyUsageSeconds); // WeeklyUsageSeconds
+ key.SetValue("LWUS", stats.LastWeekUsageSeconds); // LastWeekUsageSeconds
+
+ // 兼容性:分钟精度数据
key.SetValue("WUM", stats.WeeklyUsageMinutes); // WeeklyUsageMinutes
+ key.SetValue("LWUM", stats.LastWeekUsageMinutes); // LastWeekUsageMinutes
+
key.SetValue("WSD", stats.WeekStartDate.ToBinary()); // WeekStartDate
key.SetValue("LWLC", stats.LastWeekLaunchCount); // LastWeekLaunchCount
- key.SetValue("LWUM", stats.LastWeekUsageMinutes); // LastWeekUsageMinutes
successCount++;
LogHelper.WriteLogToFile($"DeviceIdentifier | 成功保存到备用注册表位置: {path}");
@@ -2013,15 +2271,15 @@ namespace Ink_Canvas.Helpers
{
try
{
- var (launchCount, totalMinutes, avgSession, priority) = GetUsageStats();
+ var (launchCount, totalSeconds, avgSessionSeconds, priority) = GetUsageStats();
var frequency = GetUsageFrequency();
var stats = LoadUsageStats();
var daysSinceLastUse = (DateTime.Now - stats.LastLaunchTime).TotalDays;
return $"设备ID: {DeviceId}\n" +
$"启动次数: {launchCount}\n" +
- $"总使用时长: {totalMinutes}分钟 ({totalMinutes / 60.0:F1}小时)\n" +
- $"平均会话时长: {avgSession:F1}分钟\n" +
+ $"总使用时长: {FormatDuration(totalSeconds)}\n" +
+ $"平均会话时长: {FormatDuration((long)avgSessionSeconds)}\n" +
$"使用频率: {frequency}\n" +
$"更新优先级: {priority}\n" +
$"最后使用: {daysSinceLastUse:F1}天前\n" +
@@ -2209,11 +2467,11 @@ namespace Ink_Canvas.Helpers
{
summary.AppendLine($"数据完整性: {(stats.VerifyDataIntegrity() ? "✓" : "✗")}");
summary.AppendLine($"总启动次数: {stats.LaunchCount}");
- summary.AppendLine($"总使用时长: {stats.TotalUsageMinutes}分钟 ({stats.TotalUsageMinutes / 60.0:F1}小时)");
+ summary.AppendLine($"总使用时长: {FormatDuration(stats.TotalUsageSeconds)}");
summary.AppendLine($"本周启动次数: {stats.WeeklyLaunchCount}");
- summary.AppendLine($"本周使用时长: {stats.WeeklyUsageMinutes}分钟 ({stats.WeeklyUsageMinutes / 60.0:F1}小时)");
+ summary.AppendLine($"本周使用时长: {FormatDuration(stats.WeeklyUsageSeconds)}");
summary.AppendLine($"上周启动次数: {stats.LastWeekLaunchCount}");
- summary.AppendLine($"上周使用时长: {stats.LastWeekUsageMinutes}分钟 ({stats.LastWeekUsageMinutes / 60.0:F1}小时)");
+ summary.AppendLine($"上周使用时长: {FormatDuration(stats.LastWeekUsageSeconds)}");
summary.AppendLine($"本周开始日期: {(stats.WeekStartDate != DateTime.MinValue ? stats.WeekStartDate.ToString("yyyy-MM-dd") : "未设置")}");
summary.AppendLine($"使用频率: {stats.UsageFrequency}");
summary.AppendLine($"更新优先级: {stats.UpdatePriority}");
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index ca788761..081c9693 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -5793,7 +5793,6 @@
-
Date: Mon, 28 Jul 2025 11:37:58 +0800
Subject: [PATCH 9/9] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=89=88=E6=9C=AC?=
=?UTF-8?q?=E5=8F=B7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/AssemblyInfo.cs | 4 ++--
Ink Canvas/Properties/AssemblyInfo.cs | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/Ink Canvas/AssemblyInfo.cs b/Ink Canvas/AssemblyInfo.cs
index 536f86e3..4d4146f2 100644
--- a/Ink Canvas/AssemblyInfo.cs
+++ b/Ink Canvas/AssemblyInfo.cs
@@ -49,5 +49,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.7.4.0")]
-[assembly: AssemblyFileVersion("1.7.4.0")]
+[assembly: AssemblyVersion("1.7.4.1")]
+[assembly: AssemblyFileVersion("1.7.4.1")]
diff --git a/Ink Canvas/Properties/AssemblyInfo.cs b/Ink Canvas/Properties/AssemblyInfo.cs
index aa9cd197..91fbdc2a 100644
--- a/Ink Canvas/Properties/AssemblyInfo.cs
+++ b/Ink Canvas/Properties/AssemblyInfo.cs
@@ -49,5 +49,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.7.4.0")]
-[assembly: AssemblyFileVersion("1.7.4.0")]
+[assembly: AssemblyVersion("1.7.4.1")]
+[assembly: AssemblyFileVersion("1.7.4.1")]