Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta
This commit is contained in:
@@ -237,7 +237,6 @@
|
||||
<ResourceDictionary Source="Resources/SeewoImageDictionary.xaml"/>
|
||||
<ResourceDictionary Source="Resources/DrawShapeImageDictionary.xaml"/>
|
||||
<ResourceDictionary Source="Resources/IconImageDictionary.xaml"/>
|
||||
<ResourceDictionary Source="Resources/Styles/Light.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
|
||||
@@ -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.11.1")]
|
||||
[assembly: AssemblyFileVersion("1.7.11.1")]
|
||||
[assembly: AssemblyVersion("1.7.11.3")]
|
||||
[assembly: AssemblyFileVersion("1.7.11.3")]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using Ink_Canvas.Helpers;
|
||||
|
||||
namespace Ink_Canvas
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Ink_Canvas.Helpers
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Microsoft.Office.Interop.PowerPoint;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
@@ -27,6 +26,11 @@ namespace Ink_Canvas.Helpers
|
||||
private readonly object _lockObject = new object();
|
||||
private bool _disposed;
|
||||
private string _currentActivePresentationId = "";
|
||||
|
||||
// 墨迹备份机制
|
||||
private readonly Dictionary<string, Dictionary<int, StrokeCollection>> _strokeBackups;
|
||||
private DateTime _lastBackupTime = DateTime.MinValue;
|
||||
private const int BackupIntervalMinutes = 2; // 每2分钟备份一次
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
@@ -34,6 +38,7 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
_presentationManagers = new Dictionary<string, PPTInkManager>();
|
||||
_presentationInfos = new Dictionary<string, PresentationInfo>();
|
||||
_strokeBackups = new Dictionary<string, Dictionary<int, StrokeCollection>>();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -113,8 +118,15 @@ namespace Ink_Canvas.Helpers
|
||||
var currentPresentation = GetCurrentActivePresentation();
|
||||
if (currentPresentation != null)
|
||||
{
|
||||
currentManager.SaveAllStrokesToFile(currentPresentation);
|
||||
LogHelper.WriteLogToFile($"已保存当前演示文稿墨迹: {currentPresentation.Name}", LogHelper.LogType.Trace);
|
||||
try
|
||||
{
|
||||
currentManager.SaveAllStrokesToFile(currentPresentation);
|
||||
LogHelper.WriteLogToFile($"已保存当前演示文稿墨迹: {currentPresentation.Name}", LogHelper.LogType.Trace);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"保存当前演示文稿墨迹失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,10 +139,10 @@ namespace Ink_Canvas.Helpers
|
||||
_presentationInfos[presentationId].LastAccessTime = DateTime.Now;
|
||||
}
|
||||
|
||||
if (_currentActivePresentationId != presentationId)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"已切换到演示文稿: {presentation.Name}", LogHelper.LogType.Trace);
|
||||
}
|
||||
if (_currentActivePresentationId != presentationId)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"已切换到演示文稿: {presentation.Name}", LogHelper.LogType.Trace);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -162,7 +174,17 @@ namespace Ink_Canvas.Helpers
|
||||
var manager = GetCurrentManager();
|
||||
if (manager != null)
|
||||
{
|
||||
// 保存到管理器
|
||||
manager.SaveCurrentSlideStrokes(slideIndex, strokes);
|
||||
|
||||
// 只有在保存成功后才创建备份
|
||||
if (!string.IsNullOrEmpty(_currentActivePresentationId))
|
||||
{
|
||||
CreateStrokeBackup(_currentActivePresentationId, slideIndex, strokes);
|
||||
}
|
||||
|
||||
// 检查是否需要执行定期备份
|
||||
CheckAndPerformBackup();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -210,12 +232,29 @@ namespace Ink_Canvas.Helpers
|
||||
var manager = GetCurrentManager();
|
||||
if (manager != null)
|
||||
{
|
||||
return manager.LoadSlideStrokes(slideIndex);
|
||||
var strokes = manager.LoadSlideStrokes(slideIndex);
|
||||
|
||||
// 如果从管理器加载失败,尝试从备份恢复
|
||||
if (strokes == null || strokes.Count == 0)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_currentActivePresentationId))
|
||||
{
|
||||
strokes = RestoreStrokeFromBackup(_currentActivePresentationId, slideIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return strokes ?? new StrokeCollection();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"加载页面墨迹失败: {ex}", LogHelper.LogType.Error);
|
||||
|
||||
// 尝试从备份恢复
|
||||
if (!string.IsNullOrEmpty(_currentActivePresentationId))
|
||||
{
|
||||
return RestoreStrokeFromBackup(_currentActivePresentationId, slideIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,6 +551,12 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
_presentationInfos.Remove(id);
|
||||
|
||||
// 清理备份数据
|
||||
if (_strokeBackups.ContainsKey(id))
|
||||
{
|
||||
_strokeBackups.Remove(id);
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"已清理非活跃演示文稿: {id}", LogHelper.LogType.Trace);
|
||||
}
|
||||
}
|
||||
@@ -521,6 +566,97 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建墨迹备份
|
||||
/// </summary>
|
||||
private void CreateStrokeBackup(string presentationId, int slideIndex, StrokeCollection strokes)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (strokes == null || strokes.Count == 0) return;
|
||||
|
||||
if (!_strokeBackups.ContainsKey(presentationId))
|
||||
{
|
||||
_strokeBackups[presentationId] = new Dictionary<int, StrokeCollection>();
|
||||
}
|
||||
|
||||
// 释放旧的备份
|
||||
if (_strokeBackups[presentationId].ContainsKey(slideIndex))
|
||||
{
|
||||
_strokeBackups[presentationId][slideIndex] = null;
|
||||
}
|
||||
|
||||
// 创建新的备份
|
||||
_strokeBackups[presentationId][slideIndex] = strokes.Clone();
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"创建墨迹备份失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从备份恢复墨迹
|
||||
/// </summary>
|
||||
private StrokeCollection RestoreStrokeFromBackup(string presentationId, int slideIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_strokeBackups.ContainsKey(presentationId) &&
|
||||
_strokeBackups[presentationId].ContainsKey(slideIndex))
|
||||
{
|
||||
var backup = _strokeBackups[presentationId][slideIndex];
|
||||
if (backup != null)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"从备份恢复第{slideIndex}页墨迹", LogHelper.LogType.Trace);
|
||||
return backup.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"从备份恢复墨迹失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
|
||||
return new StrokeCollection();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查并执行定期备份
|
||||
/// </summary>
|
||||
private void CheckAndPerformBackup()
|
||||
{
|
||||
try
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
|
||||
// 检查是否需要执行备份
|
||||
if (now - _lastBackupTime < TimeSpan.FromMinutes(BackupIntervalMinutes))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 备份当前活跃演示文稿的所有墨迹
|
||||
if (!string.IsNullOrEmpty(_currentActivePresentationId) &&
|
||||
_presentationManagers.ContainsKey(_currentActivePresentationId))
|
||||
{
|
||||
var manager = _presentationManagers[_currentActivePresentationId];
|
||||
if (manager != null)
|
||||
{
|
||||
// 这里可以添加更详细的备份逻辑
|
||||
LogHelper.WriteLogToFile($"执行定期墨迹备份: {_currentActivePresentationId}", LogHelper.LogType.Trace);
|
||||
}
|
||||
}
|
||||
|
||||
_lastBackupTime = now;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"定期备份检查失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
@@ -562,7 +698,7 @@ namespace Ink_Canvas.Helpers
|
||||
var presentationPath = presentation.FullName;
|
||||
var fileHash = GetFileHash(presentationPath);
|
||||
var processId = GetProcessId(presentation);
|
||||
return $"{presentation.Name}_{fileHash}_{processId}";
|
||||
return $"{presentation.Name}_{presentation.Slides.Count}_{fileHash}_{processId}";
|
||||
}
|
||||
catch (COMException comEx)
|
||||
{
|
||||
@@ -638,12 +774,24 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
// 释放所有管理器
|
||||
foreach (var manager in _presentationManagers.Values)
|
||||
{
|
||||
manager?.Dispose();
|
||||
}
|
||||
_presentationManagers.Clear();
|
||||
_presentationInfos.Clear();
|
||||
|
||||
// 清理备份数据
|
||||
foreach (var backupDict in _strokeBackups.Values)
|
||||
{
|
||||
foreach (var backup in backupDict.Values)
|
||||
{
|
||||
backup?.Clear();
|
||||
}
|
||||
backupDict.Clear();
|
||||
}
|
||||
_strokeBackups.Clear();
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,12 @@ namespace Ink_Canvas.Helpers
|
||||
private DateTime _lastSwitchTime = DateTime.MinValue;
|
||||
private int _lastSwitchSlideIndex = -1;
|
||||
private const int MinSwitchIntervalMs = 100; // 最小切换间隔100毫秒
|
||||
|
||||
// 内存管理相关字段
|
||||
private long _totalMemoryUsage = 0;
|
||||
private const long MaxMemoryUsageBytes = 100 * 1024 * 1024; // 100MB限制
|
||||
private DateTime _lastMemoryCleanup = DateTime.MinValue;
|
||||
private const int MemoryCleanupIntervalMinutes = 5; // 5分钟清理一次
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
@@ -118,24 +124,34 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
if (DateTime.Now < _inkLockUntil)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"墨迹写入被锁定,当前页:{slideIndex},锁定页:{_lockedSlideIndex}", LogHelper.LogType.Warning);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (slideIndex < _memoryStreams.Length)
|
||||
{
|
||||
// 先释放旧的内存流,防止内存泄漏
|
||||
try
|
||||
{
|
||||
_memoryStreams[slideIndex]?.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"释放旧内存流失败: {ex}", LogHelper.LogType.Warning);
|
||||
}
|
||||
|
||||
// 创建新的内存流
|
||||
var ms = new MemoryStream();
|
||||
strokes.Save(ms);
|
||||
ms.Position = 0;
|
||||
|
||||
// 释放旧的内存流
|
||||
_memoryStreams[slideIndex]?.Dispose();
|
||||
_memoryStreams[slideIndex] = ms;
|
||||
|
||||
if (ms.Length > 0)
|
||||
{
|
||||
}
|
||||
|
||||
// 检查内存使用情况
|
||||
CheckAndPerformMemoryCleanup();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -158,12 +174,20 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
if (slideIndex < _memoryStreams.Length)
|
||||
{
|
||||
// 先释放旧的内存流,防止内存泄漏
|
||||
try
|
||||
{
|
||||
_memoryStreams[slideIndex]?.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"释放旧内存流失败: {ex}", LogHelper.LogType.Warning);
|
||||
}
|
||||
|
||||
// 创建新的内存流
|
||||
var ms = new MemoryStream();
|
||||
strokes.Save(ms);
|
||||
ms.Position = 0;
|
||||
|
||||
// 释放旧的内存流
|
||||
_memoryStreams[slideIndex]?.Dispose();
|
||||
_memoryStreams[slideIndex] = ms;
|
||||
|
||||
LogHelper.WriteLogToFile($"已强制保存第{slideIndex}页墨迹,大小: {ms.Length} bytes", LogHelper.LogType.Trace);
|
||||
@@ -388,13 +412,30 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < _memoryStreams.Length; i++)
|
||||
// 安全释放所有内存流
|
||||
if (_memoryStreams != null)
|
||||
{
|
||||
_memoryStreams[i]?.Dispose();
|
||||
_memoryStreams[i] = null;
|
||||
for (int i = 0; i < _memoryStreams.Length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
_memoryStreams[i]?.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"释放内存流{i}失败: {ex}", LogHelper.LogType.Warning);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_memoryStreams[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 重新初始化数组
|
||||
_memoryStreams = new MemoryStream[_maxSlides + 2];
|
||||
}
|
||||
|
||||
CurrentStrokes.Clear();
|
||||
CurrentStrokes?.Clear();
|
||||
LogHelper.WriteLogToFile("已清除所有墨迹", LogHelper.LogType.Trace);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -430,6 +471,13 @@ namespace Ink_Canvas.Helpers
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果当前页面不是锁定页面,但锁定时间很短(小于50ms),允许写入
|
||||
// 这样可以确保旧页面的墨迹能够及时保存
|
||||
if (DateTime.Now - (_inkLockUntil.AddMilliseconds(-InkLockMilliseconds)) < TimeSpan.FromMilliseconds(50))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 只有在快速切换且页面不同时才锁定
|
||||
return false;
|
||||
}
|
||||
@@ -447,6 +495,110 @@ namespace Ink_Canvas.Helpers
|
||||
_lastSwitchSlideIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查并执行内存清理
|
||||
/// </summary>
|
||||
private void CheckAndPerformMemoryCleanup()
|
||||
{
|
||||
try
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
|
||||
// 检查是否需要执行内存清理
|
||||
if (now - _lastMemoryCleanup < TimeSpan.FromMinutes(MemoryCleanupIntervalMinutes))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算当前内存使用量
|
||||
long currentMemoryUsage = 0;
|
||||
if (_memoryStreams != null)
|
||||
{
|
||||
for (int i = 0; i < _memoryStreams.Length; i++)
|
||||
{
|
||||
if (_memoryStreams[i] != null)
|
||||
{
|
||||
currentMemoryUsage += _memoryStreams[i].Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_totalMemoryUsage = currentMemoryUsage;
|
||||
|
||||
// 如果内存使用量超过限制,执行清理
|
||||
if (currentMemoryUsage > MaxMemoryUsageBytes)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"内存使用量超限 ({currentMemoryUsage / 1024 / 1024}MB),开始清理", LogHelper.LogType.Warning);
|
||||
|
||||
// 清理非当前页面的墨迹
|
||||
CleanupInactiveSlideStrokes();
|
||||
|
||||
_lastMemoryCleanup = now;
|
||||
LogHelper.WriteLogToFile($"内存清理完成,当前使用量: {_totalMemoryUsage / 1024 / 1024}MB", LogHelper.LogType.Trace);
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastMemoryCleanup = now;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"内存清理检查失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理非活跃页面的墨迹
|
||||
/// </summary>
|
||||
private void CleanupInactiveSlideStrokes()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_memoryStreams == null) return;
|
||||
|
||||
int cleanedCount = 0;
|
||||
long freedMemory = 0;
|
||||
|
||||
for (int i = 0; i < _memoryStreams.Length; i++)
|
||||
{
|
||||
// 保留当前锁定页面和最近访问的页面
|
||||
if (i == _lockedSlideIndex || i == _lastSwitchSlideIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_memoryStreams[i] != null)
|
||||
{
|
||||
long memorySize = _memoryStreams[i].Length;
|
||||
|
||||
try
|
||||
{
|
||||
_memoryStreams[i].Dispose();
|
||||
freedMemory += memorySize;
|
||||
cleanedCount++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"清理页面{i}墨迹失败: {ex}", LogHelper.LogType.Warning);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_memoryStreams[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cleanedCount > 0)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"已清理{cleanedCount}个页面的墨迹,释放内存: {freedMemory / 1024}KB", LogHelper.LogType.Trace);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"清理非活跃页面墨迹失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
@@ -456,7 +608,7 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
var presentationPath = presentation.FullName;
|
||||
var fileHash = GetFileHash(presentationPath);
|
||||
return $"{presentation.Name}_{fileHash}";
|
||||
return $"{presentation.Name}_{presentation.Slides.Count}_{fileHash}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -93,7 +93,6 @@ namespace Ink_Canvas.Helpers
|
||||
// COM对象已失效,触发断开连接
|
||||
DisconnectFromPPT();
|
||||
}
|
||||
LogHelper.WriteLogToFile($"验证PPT放映窗口失败: {comEx.Message} (HR: 0x{hr:X8})", LogHelper.LogType.Warning);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -411,63 +410,30 @@ namespace Ink_Canvas.Helpers
|
||||
catch (COMException comEx)
|
||||
{
|
||||
var hr = (uint)comEx.HResult;
|
||||
LogHelper.WriteLogToFile($"取消PPT事件注册时COM异常: {comEx.Message} (HR: 0x{hr:X8})", LogHelper.LogType.Warning);
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
// COM对象类型转换失败,通常是因为对象已经被释放
|
||||
LogHelper.WriteLogToFile("PPT COM对象已被释放,跳过事件注册取消", LogHelper.LogType.Trace);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"取消PPT事件注册时发生异常: {ex}", LogHelper.LogType.Warning);
|
||||
}
|
||||
}, DispatcherPriority.Normal, CancellationToken.None, TimeSpan.FromSeconds(1));
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"取消PPT事件注册失败: {ex}", LogHelper.LogType.Warning);
|
||||
}
|
||||
|
||||
// 释放COM对象
|
||||
try
|
||||
{
|
||||
if (Marshal.IsComObject(CurrentSlide))
|
||||
{
|
||||
Marshal.ReleaseComObject(CurrentSlide);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (Marshal.IsComObject(CurrentSlides))
|
||||
{
|
||||
Marshal.ReleaseComObject(CurrentSlides);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (Marshal.IsComObject(CurrentPresentation))
|
||||
{
|
||||
Marshal.ReleaseComObject(CurrentPresentation);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (Marshal.IsComObject(PPTApplication))
|
||||
{
|
||||
Marshal.ReleaseComObject(PPTApplication);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
// 安全释放COM对象
|
||||
SafeReleaseComObject(CurrentSlide, "CurrentSlide");
|
||||
SafeReleaseComObject(CurrentSlides, "CurrentSlides");
|
||||
SafeReleaseComObject(CurrentPresentation, "CurrentPresentation");
|
||||
SafeReleaseComObject(PPTApplication, "PPTApplication");
|
||||
|
||||
// 清理引用
|
||||
PPTApplication = null;
|
||||
@@ -491,6 +457,30 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安全释放COM对象
|
||||
/// </summary>
|
||||
private void SafeReleaseComObject(object comObject, string objectName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (comObject != null && Marshal.IsComObject(comObject))
|
||||
{
|
||||
int refCount = Marshal.ReleaseComObject(comObject);
|
||||
LogHelper.WriteLogToFile($"已释放COM对象 {objectName},引用计数: {refCount}", LogHelper.LogType.Trace);
|
||||
}
|
||||
}
|
||||
catch (COMException comEx)
|
||||
{
|
||||
var hr = (uint)comEx.HResult;
|
||||
LogHelper.WriteLogToFile($"释放COM对象 {objectName} 时COM异常: {comEx.Message} (HR: 0x{hr:X8})", LogHelper.LogType.Warning);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"释放COM对象 {objectName} 时发生异常: {ex}", LogHelper.LogType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCurrentPresentationInfo()
|
||||
{
|
||||
try
|
||||
@@ -859,10 +849,23 @@ namespace Ink_Canvas.Helpers
|
||||
// 如果在放映模式,获取放映窗口的演示文稿
|
||||
if (IsInSlideShow && PPTApplication.SlideShowWindows.Count > 0)
|
||||
{
|
||||
var slideShowWindow = PPTApplication.SlideShowWindows[1];
|
||||
if (slideShowWindow?.View != null)
|
||||
try
|
||||
{
|
||||
return (Presentation)slideShowWindow.View.Slide.Parent;
|
||||
var slideShowWindow = PPTApplication.SlideShowWindows[1];
|
||||
if (slideShowWindow?.View != null)
|
||||
{
|
||||
return (Presentation)slideShowWindow.View.Slide.Parent;
|
||||
}
|
||||
}
|
||||
catch (COMException comEx)
|
||||
{
|
||||
var hr = (uint)comEx.HResult;
|
||||
if (hr == 0x80048240) // Integer out of range
|
||||
{
|
||||
// 放映窗口已不存在,返回null
|
||||
return null;
|
||||
}
|
||||
throw; // 重新抛出其他COM异常
|
||||
}
|
||||
}
|
||||
|
||||
@@ -935,12 +938,10 @@ namespace Ink_Canvas.Helpers
|
||||
// COM对象已失效,触发断开连接
|
||||
DisconnectFromPPT();
|
||||
}
|
||||
LogHelper.WriteLogToFile($"获取当前幻灯片编号失败: {comEx.Message}", LogHelper.LogType.Warning);
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"获取当前幻灯片编号失败: {ex}", LogHelper.LogType.Error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,6 @@ namespace Ink_Canvas.Helpers
|
||||
// 页数无效时清空页码显示
|
||||
_mainWindow.PPTBtnPageNow.Text = "?";
|
||||
_mainWindow.PPTBtnPageTotal.Text = "/ ?";
|
||||
LogHelper.WriteLogToFile($"PPT页数无效,清空页码显示: 当前页={currentSlide}, 总页数={totalSlides}", LogHelper.LogType.Warning);
|
||||
}
|
||||
|
||||
UpdateNavigationPanelsVisibility();
|
||||
@@ -132,7 +131,6 @@ namespace Ink_Canvas.Helpers
|
||||
// 页数无效时清空页码显示
|
||||
_mainWindow.PPTBtnPageNow.Text = "?";
|
||||
_mainWindow.PPTBtnPageTotal.Text = "/ ?";
|
||||
LogHelper.WriteLogToFile($"PPT页数无效,清空页码显示: 当前页={currentSlide}, 总页数={totalSlides}", LogHelper.LogType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Interop;
|
||||
|
||||
+203
-189
File diff suppressed because it is too large
Load Diff
@@ -457,8 +457,30 @@ namespace Ink_Canvas
|
||||
// HasNewUpdateWindow hasNewUpdateWindow = new HasNewUpdateWindow();
|
||||
if (Environment.Is64BitProcess) GroupBoxInkRecognition.Visibility = Visibility.Collapsed;
|
||||
|
||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
|
||||
SystemEvents_UserPreferenceChanged(null, null);
|
||||
// 根据设置应用主题
|
||||
switch (Settings.Appearance.Theme)
|
||||
{
|
||||
case 0: // 浅色主题
|
||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
|
||||
SetTheme("Light");
|
||||
break;
|
||||
case 1: // 深色主题
|
||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
|
||||
SetTheme("Dark");
|
||||
break;
|
||||
case 2: // 跟随系统
|
||||
if (IsSystemThemeLight())
|
||||
{
|
||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
|
||||
SetTheme("Light");
|
||||
}
|
||||
else
|
||||
{
|
||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
|
||||
SetTheme("Dark");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//TextBlockVersion.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
LogHelper.WriteLogToFile("Ink Canvas Loaded", LogHelper.LogType.Event);
|
||||
@@ -2741,5 +2763,123 @@ namespace Ink_Canvas
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Theme Toggle
|
||||
|
||||
/// <summary>
|
||||
/// 主题下拉框选择变化事件
|
||||
/// </summary>
|
||||
private void ComboBoxTheme_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
|
||||
try
|
||||
{
|
||||
System.Windows.Controls.ComboBox comboBox = sender as System.Windows.Controls.ComboBox;
|
||||
if (comboBox != null)
|
||||
{
|
||||
Settings.Appearance.Theme = comboBox.SelectedIndex;
|
||||
|
||||
// 应用新主题
|
||||
ApplyTheme(comboBox.SelectedIndex);
|
||||
|
||||
// 保存设置
|
||||
SaveSettingsToFile();
|
||||
|
||||
// 显示通知
|
||||
string themeName;
|
||||
switch (comboBox.SelectedIndex)
|
||||
{
|
||||
case 0:
|
||||
themeName = "浅色主题";
|
||||
break;
|
||||
case 1:
|
||||
themeName = "深色主题";
|
||||
break;
|
||||
case 2:
|
||||
themeName = "跟随系统";
|
||||
break;
|
||||
default:
|
||||
themeName = "未知主题";
|
||||
break;
|
||||
}
|
||||
|
||||
ShowNotification($"已切换到{themeName}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"切换主题时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
ShowNotification("主题切换失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用指定主题
|
||||
/// </summary>
|
||||
/// <param name="themeIndex">主题索引:0-浅色,1-深色,2-跟随系统</param>
|
||||
private void ApplyTheme(int themeIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (themeIndex)
|
||||
{
|
||||
case 0: // 浅色主题
|
||||
SetTheme("Light");
|
||||
// 浅色主题下设置浮动栏为完全不透明
|
||||
ViewboxFloatingBar.Opacity = 1.0;
|
||||
break;
|
||||
case 1: // 深色主题
|
||||
SetTheme("Dark");
|
||||
// 深色主题下设置浮动栏为完全不透明
|
||||
ViewboxFloatingBar.Opacity = 1.0;
|
||||
break;
|
||||
case 2: // 跟随系统
|
||||
if (IsSystemThemeLight())
|
||||
{
|
||||
SetTheme("Light");
|
||||
ViewboxFloatingBar.Opacity = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetTheme("Dark");
|
||||
ViewboxFloatingBar.Opacity = 1.0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 强制刷新通知框的颜色资源
|
||||
RefreshNotificationColors();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"应用主题时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新通知框的颜色资源
|
||||
/// </summary>
|
||||
private void RefreshNotificationColors()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 强制刷新通知框的背景和前景色
|
||||
var border = GridNotifications.Children.OfType<Border>().FirstOrDefault();
|
||||
if (border != null)
|
||||
{
|
||||
border.Background = (Brush)Application.Current.FindResource("SettingsPageBackground");
|
||||
border.BorderBrush = new SolidColorBrush(Color.FromRgb(185, 28, 28)); // 保持红色边框
|
||||
}
|
||||
|
||||
TextBlockNotice.Foreground = (Brush)Application.Current.FindResource("SettingsPageForeground");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"刷新通知框颜色时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using iNKORE.UI.WPF.Modern;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Application = System.Windows.Application;
|
||||
@@ -9,16 +10,34 @@ namespace Ink_Canvas
|
||||
{
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private Color FloatBarForegroundColor = Color.FromRgb(102, 102, 102);
|
||||
private Color FloatBarForegroundColor;
|
||||
|
||||
private void SetTheme(string theme)
|
||||
{
|
||||
// 清理现有的主题资源
|
||||
var resourcesToRemove = new List<ResourceDictionary>();
|
||||
foreach (var dict in Application.Current.Resources.MergedDictionaries)
|
||||
{
|
||||
if (dict.Source != null &&
|
||||
(dict.Source.ToString().Contains("Light.xaml") ||
|
||||
dict.Source.ToString().Contains("Dark.xaml")))
|
||||
{
|
||||
resourcesToRemove.Add(dict);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var dict in resourcesToRemove)
|
||||
{
|
||||
Application.Current.Resources.MergedDictionaries.Remove(dict);
|
||||
}
|
||||
|
||||
if (theme == "Light")
|
||||
{
|
||||
var rd1 = new ResourceDictionary
|
||||
{ Source = new Uri("Resources/Styles/Light.xaml", UriKind.Relative) };
|
||||
Application.Current.Resources.MergedDictionaries.Add(rd1);
|
||||
|
||||
|
||||
// 在主题资源之后添加其他资源
|
||||
var rd2 = new ResourceDictionary
|
||||
{ Source = new Uri("Resources/DrawShapeImageDictionary.xaml", UriKind.Relative) };
|
||||
Application.Current.Resources.MergedDictionaries.Add(rd2);
|
||||
@@ -33,13 +52,17 @@ namespace Ink_Canvas
|
||||
|
||||
ThemeManager.SetRequestedTheme(window, ElementTheme.Light);
|
||||
|
||||
FloatBarForegroundColor = (Color)Application.Current.FindResource("FloatBarForegroundColor");
|
||||
InitializeFloatBarForegroundColor();
|
||||
|
||||
// 强制刷新UI
|
||||
window.InvalidateVisual();
|
||||
}
|
||||
else if (theme == "Dark")
|
||||
{
|
||||
var rd1 = new ResourceDictionary { Source = new Uri("Resources/Styles/Dark.xaml", UriKind.Relative) };
|
||||
Application.Current.Resources.MergedDictionaries.Add(rd1);
|
||||
|
||||
|
||||
// 在主题资源之后添加其他资源
|
||||
var rd2 = new ResourceDictionary
|
||||
{ Source = new Uri("Resources/DrawShapeImageDictionary.xaml", UriKind.Relative) };
|
||||
Application.Current.Resources.MergedDictionaries.Add(rd2);
|
||||
@@ -54,7 +77,93 @@ namespace Ink_Canvas
|
||||
|
||||
ThemeManager.SetRequestedTheme(window, ElementTheme.Dark);
|
||||
|
||||
InitializeFloatBarForegroundColor();
|
||||
|
||||
// 强制刷新UI
|
||||
window.InvalidateVisual();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化FloatBarForegroundColor,从当前主题资源中加载颜色
|
||||
/// </summary>
|
||||
private void InitializeFloatBarForegroundColor()
|
||||
{
|
||||
try
|
||||
{
|
||||
FloatBarForegroundColor = (Color)Application.Current.FindResource("FloatBarForegroundColor");
|
||||
|
||||
// 强制刷新浮动工具栏按钮颜色
|
||||
RefreshFloatingBarButtonColors();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 如果无法从资源中加载,使用默认颜色
|
||||
FloatBarForegroundColor = Color.FromRgb(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新浮动工具栏按钮颜色
|
||||
/// </summary>
|
||||
private void RefreshFloatingBarButtonColors()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 选中状态的颜色(蓝底)
|
||||
var selectedColor = Color.FromRgb(30, 58, 138);
|
||||
|
||||
// 根据当前模式设置按钮颜色
|
||||
switch (_currentToolMode)
|
||||
{
|
||||
case "cursor":
|
||||
CursorIconGeometry.Brush = new SolidColorBrush(selectedColor);
|
||||
PenIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
StrokeEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
CircleEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
LassoSelectIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
break;
|
||||
case "pen":
|
||||
case "color":
|
||||
CursorIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
PenIconGeometry.Brush = new SolidColorBrush(selectedColor);
|
||||
StrokeEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
CircleEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
LassoSelectIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
break;
|
||||
case "eraser":
|
||||
CursorIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
PenIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
StrokeEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
CircleEraserIconGeometry.Brush = new SolidColorBrush(selectedColor);
|
||||
LassoSelectIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
break;
|
||||
case "eraserByStrokes":
|
||||
CursorIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
PenIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
StrokeEraserIconGeometry.Brush = new SolidColorBrush(selectedColor);
|
||||
CircleEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
LassoSelectIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
break;
|
||||
case "select":
|
||||
CursorIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
PenIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
StrokeEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
CircleEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
LassoSelectIconGeometry.Brush = new SolidColorBrush(selectedColor);
|
||||
break;
|
||||
default:
|
||||
// 默认情况,所有按钮都使用主题颜色
|
||||
CursorIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
PenIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
StrokeEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
CircleEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
LassoSelectIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,11 +84,23 @@ namespace Ink_Canvas
|
||||
EnableTwoFingerGestureBtn.Source =
|
||||
new BitmapImage(new Uri("/Resources/new-icons/gesture.png", UriKind.Relative));
|
||||
|
||||
BoardGesture.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardGestureGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGestureGeometry2.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGestureLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGesture.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
// 根据主题设置颜色
|
||||
if (Settings.Appearance.Theme == 1) // 深色主题
|
||||
{
|
||||
BoardGesture.Background = new SolidColorBrush(Color.FromRgb(42, 42, 42));
|
||||
BoardGestureGeometry.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardGestureGeometry2.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardGestureLabel.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardGesture.BorderBrush = new SolidColorBrush(Color.FromRgb(85, 85, 85));
|
||||
}
|
||||
else // 浅色主题或跟随系统
|
||||
{
|
||||
BoardGesture.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardGestureGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGestureGeometry2.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGestureLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGesture.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
}
|
||||
BoardGestureGeometry.Geometry = Geometry.Parse(XamlGraphicsIconGeometries.DisabledGestureIcon);
|
||||
BoardGestureGeometry2.Geometry = Geometry.Parse("F0 M24,24z M0,0z");
|
||||
|
||||
@@ -122,11 +134,23 @@ namespace Ink_Canvas
|
||||
EnableTwoFingerGestureBtn.Source =
|
||||
new BitmapImage(new Uri("/Resources/new-icons/gesture.png", UriKind.Relative));
|
||||
|
||||
BoardGesture.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardGestureGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGestureGeometry2.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGestureLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGesture.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
// 根据主题设置颜色
|
||||
if (Settings.Appearance.Theme == 1) // 深色主题
|
||||
{
|
||||
BoardGesture.Background = new SolidColorBrush(Color.FromRgb(42, 42, 42));
|
||||
BoardGestureGeometry.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardGestureGeometry2.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardGestureLabel.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardGesture.BorderBrush = new SolidColorBrush(Color.FromRgb(85, 85, 85));
|
||||
}
|
||||
else // 浅色主题或跟随系统
|
||||
{
|
||||
BoardGesture.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardGestureGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGestureGeometry2.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGestureLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardGesture.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
}
|
||||
BoardGestureGeometry.Geometry = Geometry.Parse(XamlGraphicsIconGeometries.DisabledGestureIcon);
|
||||
BoardGestureGeometry2.Geometry = Geometry.Parse("F0 M24,24z M0,0z");
|
||||
}
|
||||
@@ -404,31 +428,50 @@ namespace Ink_Canvas
|
||||
{
|
||||
if (mode != "clear")
|
||||
{
|
||||
CursorIconGeometry.Brush = new SolidColorBrush(Color.FromRgb(27, 27, 27));
|
||||
CursorIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
CursorIconGeometry.Geometry = Geometry.Parse(XamlGraphicsIconGeometries.LinedCursorIcon);
|
||||
PenIconGeometry.Brush = new SolidColorBrush(Color.FromRgb(27, 27, 27));
|
||||
PenIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
PenIconGeometry.Geometry = Geometry.Parse(XamlGraphicsIconGeometries.LinedPenIcon);
|
||||
StrokeEraserIconGeometry.Brush = new SolidColorBrush(Color.FromRgb(27, 27, 27));
|
||||
StrokeEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
StrokeEraserIconGeometry.Geometry =
|
||||
Geometry.Parse(XamlGraphicsIconGeometries.LinedEraserStrokeIcon);
|
||||
CircleEraserIconGeometry.Brush = new SolidColorBrush(Color.FromRgb(27, 27, 27));
|
||||
CircleEraserIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
CircleEraserIconGeometry.Geometry =
|
||||
Geometry.Parse(XamlGraphicsIconGeometries.LinedEraserCircleIcon);
|
||||
LassoSelectIconGeometry.Brush = new SolidColorBrush(Color.FromRgb(27, 27, 27));
|
||||
LassoSelectIconGeometry.Brush = new SolidColorBrush(FloatBarForegroundColor);
|
||||
LassoSelectIconGeometry.Geometry = Geometry.Parse(XamlGraphicsIconGeometries.LinedLassoSelectIcon);
|
||||
|
||||
BoardPen.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardSelect.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardEraser.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardSelectGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardPenGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardEraserGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardPenLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardSelectLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardEraserLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardSelect.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
BoardEraser.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
BoardPen.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
// 根据主题设置颜色
|
||||
if (Settings.Appearance.Theme == 1) // 深色主题
|
||||
{
|
||||
BoardPen.Background = new SolidColorBrush(Color.FromRgb(42, 42, 42));
|
||||
BoardSelect.Background = new SolidColorBrush(Color.FromRgb(42, 42, 42));
|
||||
BoardEraser.Background = new SolidColorBrush(Color.FromRgb(42, 42, 42));
|
||||
BoardSelectGeometry.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardPenGeometry.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardEraserGeometry.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardPenLabel.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardSelectLabel.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardEraserLabel.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardSelect.BorderBrush = new SolidColorBrush(Color.FromRgb(85, 85, 85));
|
||||
BoardEraser.BorderBrush = new SolidColorBrush(Color.FromRgb(85, 85, 85));
|
||||
BoardPen.BorderBrush = new SolidColorBrush(Color.FromRgb(85, 85, 85));
|
||||
}
|
||||
else // 浅色主题或跟随系统
|
||||
{
|
||||
BoardPen.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardSelect.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardEraser.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardSelectGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardPenGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardEraserGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardPenLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardSelectLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardEraserLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardSelect.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
BoardEraser.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
BoardPen.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
}
|
||||
|
||||
HideFloatingBarHighlight();
|
||||
}
|
||||
@@ -492,10 +535,21 @@ namespace Ink_Canvas
|
||||
CursorIconGeometry.Brush = new SolidColorBrush(Color.FromRgb(30, 58, 138));
|
||||
CursorIconGeometry.Geometry =
|
||||
Geometry.Parse(XamlGraphicsIconGeometries.LinedCursorIcon);
|
||||
BoardPen.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardPen.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
BoardPenGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardPenLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
// 根据主题设置颜色
|
||||
if (Settings.Appearance.Theme == 1) // 深色主题
|
||||
{
|
||||
BoardPen.Background = new SolidColorBrush(Color.FromRgb(42, 42, 42));
|
||||
BoardPen.BorderBrush = new SolidColorBrush(Color.FromRgb(85, 85, 85));
|
||||
BoardPenGeometry.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
BoardPenLabel.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
}
|
||||
else // 浅色主题或跟随系统
|
||||
{
|
||||
BoardPen.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245));
|
||||
BoardPen.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
|
||||
BoardPenGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
BoardPenLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
|
||||
}
|
||||
|
||||
SetFloatingBarHighlightPosition("cursor");
|
||||
break;
|
||||
|
||||
@@ -3,7 +3,6 @@ using iNKORE.UI.WPF.Modern.Controls;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Ink_Canvas
|
||||
{
|
||||
|
||||
@@ -1121,14 +1121,42 @@ namespace Ink_Canvas
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查PPT连接状态
|
||||
if (_pptManager?.IsConnected != true || _pptManager?.IsInSlideShow != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取当前页面索引
|
||||
var currentSlideIndex = _pptManager?.GetCurrentSlideNumber() ?? 0;
|
||||
|
||||
|
||||
// 验证页面索引的有效性
|
||||
if (newSlideIndex <= 0)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"无效的新页面索引: {newSlideIndex},跳过页面切换", LogHelper.LogType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果有当前墨迹且不是第一次切换,先保存到当前页面
|
||||
if (inkCanvas.Strokes.Count > 0 && currentSlideIndex > 0 && currentSlideIndex != newSlideIndex)
|
||||
{
|
||||
_multiPPTInkManager?.SaveCurrentSlideStrokes(currentSlideIndex, inkCanvas.Strokes);
|
||||
LogHelper.WriteLogToFile($"切换前保存第{currentSlideIndex}页墨迹,墨迹数量: {inkCanvas.Strokes.Count}", LogHelper.LogType.Trace);
|
||||
// 检查是否可以写入墨迹
|
||||
bool canWrite = _multiPPTInkManager?.CanWriteInk(currentSlideIndex) == true;
|
||||
|
||||
if (canWrite)
|
||||
{
|
||||
// 正常保存
|
||||
_multiPPTInkManager?.SaveCurrentSlideStrokes(currentSlideIndex, inkCanvas.Strokes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 墨迹被锁定,跳过保存以避免墨迹错页
|
||||
}
|
||||
}
|
||||
else if (inkCanvas.Strokes.Count > 0 && currentSlideIndex <= 0)
|
||||
{
|
||||
// 无法获取当前页面索引时,不保存墨迹,直接清空
|
||||
}
|
||||
|
||||
// 切换到新页面并加载墨迹
|
||||
@@ -1139,8 +1167,7 @@ namespace Ink_Canvas
|
||||
inkCanvas.Strokes.Add(newStrokes);
|
||||
}
|
||||
|
||||
// 设置墨迹锁定
|
||||
_multiPPTInkManager?.LockInkForSlide(newSlideIndex);
|
||||
// 注意:LockInkForSlide已经在SwitchToSlide中调用,这里不需要重复调用
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -245,6 +245,9 @@ namespace Ink_Canvas
|
||||
break;
|
||||
}
|
||||
|
||||
// 设置主题下拉框
|
||||
ComboBoxTheme.SelectedIndex = Settings.Appearance.Theme;
|
||||
|
||||
ComboBoxChickenSoupSource.SelectedIndex = Settings.Appearance.ChickenSoupSource;
|
||||
|
||||
ToggleSwitchEnableQuickPanel.IsOn = Settings.Appearance.IsShowQuickPanel;
|
||||
|
||||
@@ -9,7 +9,6 @@ using System.Windows.Ink;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
using Point = System.Windows.Point;
|
||||
|
||||
namespace Ink_Canvas
|
||||
|
||||
@@ -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.11.1")]
|
||||
[assembly: AssemblyFileVersion("1.7.11.1")]
|
||||
[assembly: AssemblyVersion("1.7.11.3")]
|
||||
[assembly: AssemblyFileVersion("1.7.11.3")]
|
||||
|
||||
@@ -1,7 +1,32 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<SolidColorBrush x:Key="FloatBarBackground" Color="Black" Opacity="0.5"/>
|
||||
<SolidColorBrush x:Key="FloatBarBorderBrush" Color="White" Opacity="0.5"/>
|
||||
<SolidColorBrush x:Key="FloatBarForeground" Color="White"/>
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<SolidColorBrush x:Key="FloatBarBackground" Opacity="0.6" Color="Black" />
|
||||
<SolidColorBrush x:Key="FloatBarBackgroundWithoutOpacity" Opacity="0.95" Color="Black" />
|
||||
<SolidColorBrush x:Key="FloatBarTitleBackground" Opacity="0.5" Color="#2156c9" />
|
||||
<SolidColorBrush x:Key="FloatBarBorderBrush" Opacity="0.6" Color="White" />
|
||||
<SolidColorBrush x:Key="FloatBarForeground" Color="White" />
|
||||
<Color x:Key="FloatBarForegroundColor">#FFcccccc</Color>
|
||||
|
||||
<SolidColorBrush x:Key="SettingsPageForeground" Color="White" />
|
||||
<SolidColorBrush x:Key="SettingsPageAnnotationForeground" Opacity="0.7" Color="White" />
|
||||
<SolidColorBrush x:Key="SettingsPageBorderBrush" Opacity="0.8" Color="White" />
|
||||
<SolidColorBrush x:Key="SettingsPageBackground" Opacity="0.95" Color="#1f1f1f" />
|
||||
|
||||
<SolidColorBrush x:Key="IconForeground" Color="White" />
|
||||
<SolidColorBrush x:Key="TextForeground" Color="White" />
|
||||
|
||||
<SolidColorBrush x:Key="RedBrush" Color="IndianRed" />
|
||||
<SolidColorBrush x:Key="PurpleBrush" Color="MediumPurple" />
|
||||
|
||||
<Color x:Key="FloatBarButtonBackgroundKey">Transparent</Color>
|
||||
<Color x:Key="FloatBarButtonBackgroundPointerOverKey">#2200CDCD</Color>
|
||||
<Color x:Key="FloatBarButtonButtonBackgroundPressedKey">#4400CDCD</Color>
|
||||
|
||||
<!-- 白板模式浮动栏颜色 -->
|
||||
<SolidColorBrush x:Key="BoardFloatBarBackground" Color="#2a2a2a" />
|
||||
<SolidColorBrush x:Key="BoardFloatBarBorderBrush" Color="#555555" />
|
||||
|
||||
<!-- 白板模式按钮选中状态颜色 -->
|
||||
<SolidColorBrush x:Key="BoardFloatBarSelectedBackground" Color="#2563eb" />
|
||||
<SolidColorBrush x:Key="BoardFloatBarSelectedBorderBrush" Color="#2563eb" />
|
||||
<SolidColorBrush x:Key="BoardFloatBarSelectedForeground" Color="White" />
|
||||
</ResourceDictionary>
|
||||
@@ -1,7 +1,32 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<SolidColorBrush x:Key="FloatBarBackground" Color="#fafafa" Opacity="0.95"/>
|
||||
<SolidColorBrush x:Key="FloatBarBorderBrush" Color="#52525b" Opacity="0.6"/>
|
||||
<SolidColorBrush x:Key="FloatBarForeground" Color="#18181b"/>
|
||||
<Color x:Key="FloatBarForegroundColor">#18181b</Color>
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<SolidColorBrush x:Key="FloatBarBackground" Opacity="1.0" Color="White" />
|
||||
<SolidColorBrush x:Key="FloatBarBackgroundWithoutOpacity" Opacity="1.0" Color="White" />
|
||||
<SolidColorBrush x:Key="FloatBarTitleBackground" Opacity="0.25" Color="#588bfc" />
|
||||
<SolidColorBrush x:Key="FloatBarBorderBrush" Opacity="0.8" Color="Black" />
|
||||
<SolidColorBrush x:Key="FloatBarForeground" Color="Black" />
|
||||
<Color x:Key="FloatBarForegroundColor">#FF000000</Color>
|
||||
|
||||
<SolidColorBrush x:Key="SettingsPageForeground" Color="Black" />
|
||||
<SolidColorBrush x:Key="SettingsPageAnnotationForeground" Color="#666666" />
|
||||
<SolidColorBrush x:Key="SettingsPageBorderBrush" Opacity="0.8" Color="Black" />
|
||||
<SolidColorBrush x:Key="SettingsPageBackground" Opacity="0.95" Color="White" />
|
||||
|
||||
<SolidColorBrush x:Key="IconForeground" Color="#18181b" />
|
||||
<SolidColorBrush x:Key="TextForeground" Color="Black" />
|
||||
|
||||
<SolidColorBrush x:Key="RedBrush" Color="DarkRed" />
|
||||
<SolidColorBrush x:Key="PurpleBrush" Color="DarkBlue" />
|
||||
|
||||
<Color x:Key="FloatBarButtonBackgroundKey">Transparent</Color>
|
||||
<Color x:Key="FloatBarButtonBackgroundPointerOverKey">#66FFFFFF</Color>
|
||||
<Color x:Key="FloatBarButtonButtonBackgroundPressedKey">#99FFFFFF</Color>
|
||||
|
||||
<!-- 白板模式浮动栏颜色 -->
|
||||
<SolidColorBrush x:Key="BoardFloatBarBackground" Color="#f4f4f5" />
|
||||
<SolidColorBrush x:Key="BoardFloatBarBorderBrush" Color="#a1a1aa" />
|
||||
|
||||
<!-- 白板模式按钮选中状态颜色 -->
|
||||
<SolidColorBrush x:Key="BoardFloatBarSelectedBackground" Color="#2563eb" />
|
||||
<SolidColorBrush x:Key="BoardFloatBarSelectedBorderBrush" Color="#2563eb" />
|
||||
<SolidColorBrush x:Key="BoardFloatBarSelectedForeground" Color="White" />
|
||||
</ResourceDictionary>
|
||||
@@ -11,13 +11,13 @@
|
||||
ui:WindowHelper.SystemBackdropType="Mica"
|
||||
Title="InkCanvasForClass CE有新版本可用" Height="650" Width="900" ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterScreen" WindowStyle="None" AllowsTransparency="True"
|
||||
Background="#f8fafc">
|
||||
Background="Transparent">
|
||||
<Window.Template>
|
||||
<ControlTemplate TargetType="Window">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
<Border Background="#f8fafc"
|
||||
CornerRadius="16"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}">
|
||||
BorderBrush="Transparent"
|
||||
BorderThickness="0">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="#000000" BlurRadius="30" ShadowDepth="0" Opacity="0.15"/>
|
||||
</Border.Effect>
|
||||
@@ -140,7 +140,7 @@
|
||||
</Window.Resources>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<Grid Margin="0,0,0,0">
|
||||
<Grid Margin="0,0,0,0" Background="Transparent">
|
||||
<ui:SimpleStackPanel VerticalAlignment="Stretch" Spacing="0">
|
||||
<!-- 统一的主容器 -->
|
||||
<Border Background="White" CornerRadius="16" Margin="0,0,0,0"
|
||||
|
||||
@@ -6,19 +6,236 @@
|
||||
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
|
||||
xmlns:mdxam="clr-namespace:MdXaml;assembly=MdXaml"
|
||||
mc:Ignorable="d"
|
||||
Title="历史版本回滚" Height="600" Width="850" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
|
||||
<Grid Background="#fafafa">
|
||||
<ui:SimpleStackPanel VerticalAlignment="Stretch" Spacing="0">
|
||||
<TextBlock Text="选择历史版本进行回滚" FontSize="24" FontWeight="Bold" Foreground="#2563eb" Margin="24,24,0,12"/>
|
||||
<ComboBox x:Name="VersionComboBox" Width="400" Height="36" Margin="24,0,0,0" DisplayMemberPath="Version" SelectionChanged="VersionComboBox_SelectionChanged"/>
|
||||
<Border BorderBrush="#3f3f46" Background="White" BorderThickness="1" CornerRadius="4" Margin="24,16,24,0" Height="180">
|
||||
<mdxam:MarkdownScrollViewer x:Name="ReleaseNotesViewer" Foreground="Black" MarkdownStyleName="GithubLike"/>
|
||||
ui:WindowHelper.UseModernWindowStyle="False"
|
||||
ui:WindowHelper.SystemBackdropType="Mica"
|
||||
Title="历史版本回滚" Height="650" Width="900" ResizeMode="CanResize"
|
||||
WindowStartupLocation="CenterScreen" WindowStyle="None" AllowsTransparency="True"
|
||||
Background="Transparent" MinHeight="550" MinWidth="800">
|
||||
<Window.Template>
|
||||
<ControlTemplate TargetType="Window">
|
||||
<Border Background="#f8fafc"
|
||||
CornerRadius="16"
|
||||
BorderBrush="Transparent"
|
||||
BorderThickness="0">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="#000000" BlurRadius="30" ShadowDepth="0" Opacity="0.15"/>
|
||||
</Border.Effect>
|
||||
<Grid>
|
||||
<!-- 标题栏 -->
|
||||
<Border Background="Transparent" Height="40" VerticalAlignment="Top">
|
||||
<Grid>
|
||||
<TextBlock Text="{TemplateBinding Title}"
|
||||
FontSize="16" FontWeight="SemiBold"
|
||||
Foreground="#374151"
|
||||
VerticalAlignment="Center"
|
||||
Margin="20,0,0,0"/>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center">
|
||||
<Button Name="MinimizeButton"
|
||||
Width="40" Height="30"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Click="MinimizeButton_Click"
|
||||
Margin="0,0,2,0">
|
||||
<TextBlock Text="−" FontSize="16" Foreground="#6b7280"/>
|
||||
</Button>
|
||||
<Button Name="CloseButton"
|
||||
Width="40" Height="30"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Click="CloseButton_Click">
|
||||
<TextBlock Text="×" FontSize="16" Foreground="#6b7280"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- 内容区域 -->
|
||||
<ContentPresenter Margin="0,40,0,0"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Window.Template>
|
||||
<Window.Resources>
|
||||
<!-- 现代化按钮样式 -->
|
||||
<Style x:Key="ModernPrimaryButton" TargetType="Button">
|
||||
<Setter Property="Background" Value="#3b82f6"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="15"/>
|
||||
<Setter Property="Padding" Value="24,12"/>
|
||||
<Setter Property="Height" Value="48"/>
|
||||
<Setter Property="Width" Value="320"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
CornerRadius="12"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="#3b82f6" BlurRadius="8" ShadowDepth="0" Opacity="0.3"/>
|
||||
</Border.Effect>
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2563eb"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#1d4ed8"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="#9ca3af"/>
|
||||
<Setter Property="Foreground" Value="#6b7280"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- 现代化ComboBox样式 -->
|
||||
<Style x:Key="ModernComboBox" TargetType="ComboBox">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="Foreground" Value="#374151"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="BorderBrush" Value="#d1d5db"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Height" Value="40"/>
|
||||
<Setter Property="Padding" Value="12,8"/>
|
||||
</Style>
|
||||
|
||||
<!-- ComboBoxItem样式 -->
|
||||
<Style TargetType="ComboBoxItem">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="Foreground" Value="#374151"/>
|
||||
<Setter Property="Padding" Value="12,8"/>
|
||||
<Setter Property="Margin" Value="0,1"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ComboBoxItem">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
CornerRadius="4"
|
||||
Margin="2">
|
||||
<ContentPresenter Margin="{TemplateBinding Padding}"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#f0f9ff"/>
|
||||
<Setter Property="Foreground" Value="#1e40af"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#3b82f6"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="Transparent">
|
||||
<!-- 主内容区域 -->
|
||||
<Border Background="White" CornerRadius="16" Margin="20"
|
||||
BorderThickness="0" Padding="0">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="#000000" BlurRadius="20" ShadowDepth="0" Opacity="0.08"/>
|
||||
</Border.Effect>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<ui:SimpleStackPanel VerticalAlignment="Stretch" Spacing="0" Margin="28">
|
||||
<!-- 标题区域 -->
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" Spacing="12" Margin="0,32,0,24">
|
||||
<Border Background="#3b82f6" CornerRadius="8" Width="40" Height="40"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="↶" FontSize="20" Foreground="White"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ui:SimpleStackPanel VerticalAlignment="Center" Spacing="4">
|
||||
<TextBlock Text="历史版本回滚" FontSize="28" FontWeight="Bold"
|
||||
Foreground="#1f2937"/>
|
||||
<TextBlock Text="选择要回滚到的历史版本" FontSize="14"
|
||||
Foreground="#6b7280"/>
|
||||
</ui:SimpleStackPanel>
|
||||
</ui:SimpleStackPanel>
|
||||
|
||||
<!-- 版本选择卡片 -->
|
||||
<Border Background="#f8fafc" CornerRadius="12" Padding="20" Margin="0,0,0,20">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="#000000" BlurRadius="8" ShadowDepth="0" Opacity="0.05"/>
|
||||
</Border.Effect>
|
||||
<ui:SimpleStackPanel Spacing="12">
|
||||
<TextBlock Text="选择版本" FontSize="16" FontWeight="SemiBold"
|
||||
Foreground="#374151"/>
|
||||
<ComboBox x:Name="VersionComboBox"
|
||||
Width="400" Height="40"
|
||||
DisplayMemberPath="Version"
|
||||
SelectionChanged="VersionComboBox_SelectionChanged"
|
||||
Background="White"
|
||||
BorderBrush="#d1d5db"
|
||||
BorderThickness="1"
|
||||
FontSize="14"/>
|
||||
</ui:SimpleStackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 发布说明卡片 -->
|
||||
<Border Background="#f8fafc" CornerRadius="12" Padding="20" Margin="0,0,0,20">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="#000000" BlurRadius="8" ShadowDepth="0" Opacity="0.05"/>
|
||||
</Border.Effect>
|
||||
<ui:SimpleStackPanel Spacing="12">
|
||||
<TextBlock Text="版本更新说明" FontSize="16" FontWeight="SemiBold"
|
||||
Foreground="#374151"/>
|
||||
<Border Background="White" BorderBrush="#e5e7eb" BorderThickness="1"
|
||||
CornerRadius="8" MinHeight="200" MaxHeight="300">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
Padding="16">
|
||||
<mdxam:MarkdownScrollViewer x:Name="ReleaseNotesViewer"
|
||||
Foreground="#374151"
|
||||
MarkdownStyleName="GithubLike"/>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</ui:SimpleStackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<ui:SimpleStackPanel Spacing="16" Margin="0,0,0,32">
|
||||
<Button x:Name="RollbackButton"
|
||||
Content="回滚到此版本"
|
||||
Style="{StaticResource ModernPrimaryButton}"
|
||||
Click="RollbackButton_Click"/>
|
||||
|
||||
<!-- 下载进度面板 -->
|
||||
<StackPanel x:Name="DownloadProgressPanel"
|
||||
Orientation="Vertical"
|
||||
HorizontalAlignment="Center"
|
||||
Visibility="Collapsed"
|
||||
Margin="0,8,0,0">
|
||||
<Border Background="#f0f9ff" BorderBrush="#3b82f6"
|
||||
BorderThickness="1" CornerRadius="8" Padding="16">
|
||||
<ui:SimpleStackPanel Spacing="12">
|
||||
<ProgressBar x:Name="DownloadProgressBar"
|
||||
Width="400" Height="8"
|
||||
Minimum="0" Maximum="100" Value="0"
|
||||
Background="#e0f2fe"
|
||||
Foreground="#3b82f6"/>
|
||||
<TextBlock x:Name="DownloadProgressText"
|
||||
Text="正在下载..."
|
||||
FontSize="14"
|
||||
Foreground="#1e40af"
|
||||
HorizontalAlignment="Center"/>
|
||||
</ui:SimpleStackPanel>
|
||||
</Border>
|
||||
<Button x:Name="RollbackButton" Content="回滚到此版本" Width="360" Height="48" Margin="24,24,0,0" Click="RollbackButton_Click"/>
|
||||
<StackPanel x:Name="DownloadProgressPanel" Orientation="Vertical" HorizontalAlignment="Center" Margin="0,10,0,0" Visibility="Collapsed">
|
||||
<ProgressBar x:Name="DownloadProgressBar" Width="360" Height="18" Minimum="0" Maximum="100" Value="0"/>
|
||||
<TextBlock x:Name="DownloadProgressText" Text="正在下载..." FontSize="14" Foreground="#2563eb" HorizontalAlignment="Center" Margin="0,6,0,0"/>
|
||||
</StackPanel>
|
||||
</ui:SimpleStackPanel>
|
||||
</ui:SimpleStackPanel>
|
||||
</ui:SimpleStackPanel>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
</Window>
|
||||
@@ -32,6 +32,15 @@ namespace Ink_Canvas
|
||||
InitializeComponent();
|
||||
this.channel = channel;
|
||||
LoadVersions();
|
||||
|
||||
// 添加窗口拖动功能
|
||||
this.MouseDown += (sender, e) =>
|
||||
{
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
{
|
||||
this.DragMove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private async void LoadVersions()
|
||||
@@ -135,6 +144,16 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
private void MinimizeButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
private void CloseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
downloadCts?.Cancel();
|
||||
|
||||
Reference in New Issue
Block a user