From 21932056f3169113274a4271b3ef02c932ddb13e Mon Sep 17 00:00:00 2001 From: CJKmkp <2564608840@qq.com> Date: Sun, 31 Aug 2025 13:14:05 +0800 Subject: [PATCH 01/50] =?UTF-8?q?improve:=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Helpers/Plugins/EnhancedPluginBaseV2.cs | 241 ++++++++ Ink Canvas/Helpers/Plugins/IActionService.cs | 296 ++++++++++ Ink Canvas/Helpers/Plugins/IGetService.cs | 215 ++++++++ Ink Canvas/Helpers/Plugins/IPluginService.cs | 521 +----------------- Ink Canvas/Helpers/Plugins/IWindowService.cs | 154 ++++++ .../Helpers/Plugins/PluginServiceManager.cs | 282 ++++++---- 6 files changed, 1078 insertions(+), 631 deletions(-) create mode 100644 Ink Canvas/Helpers/Plugins/EnhancedPluginBaseV2.cs create mode 100644 Ink Canvas/Helpers/Plugins/IActionService.cs create mode 100644 Ink Canvas/Helpers/Plugins/IGetService.cs create mode 100644 Ink Canvas/Helpers/Plugins/IWindowService.cs diff --git a/Ink Canvas/Helpers/Plugins/EnhancedPluginBaseV2.cs b/Ink Canvas/Helpers/Plugins/EnhancedPluginBaseV2.cs new file mode 100644 index 00000000..d4f2f96f --- /dev/null +++ b/Ink Canvas/Helpers/Plugins/EnhancedPluginBaseV2.cs @@ -0,0 +1,241 @@ +using System.Windows.Controls; + +namespace Ink_Canvas.Helpers.Plugins +{ + /// + /// 增强的插件基类 V2,提供对三个专门服务接口的访问 + /// 插件开发者可以根据需要选择性地使用这些服务 + /// + public abstract class EnhancedPluginBaseV2 : PluginBase, IEnhancedPlugin + { + /// + /// 获取服务实例 + /// + public IGetService GetService { get; private set; } + + /// + /// 窗口服务实例 + /// + public IWindowService WindowService { get; private set; } + + /// + /// 操作服务实例 + /// + public IActionService ActionService { get; private set; } + + /// + /// 插件服务实例(兼容性) + /// + public IPluginService PluginService { get; private set; } + + /// + /// 构造函数 + /// + protected EnhancedPluginBaseV2() + { + // 初始化所有服务实例 + PluginService = PluginServiceManager.Instance; + GetService = PluginServiceManager.Instance; + WindowService = PluginServiceManager.Instance; + ActionService = PluginServiceManager.Instance; + } + + /// + /// 插件启动时调用,在Initialize之后 + /// + public virtual void OnStartup() + { + LogHelper.WriteLogToFile($"插件 {Name} 已启动"); + } + + /// + /// 插件关闭时调用,在Cleanup之前 + /// + public virtual void OnShutdown() + { + LogHelper.WriteLogToFile($"插件 {Name} 正在关闭"); + } + + /// + /// 获取插件的菜单项 + /// + /// 菜单项集合 + public virtual MenuItem[] GetMenuItems() + { + return new MenuItem[0]; + } + + /// + /// 获取插件的工具栏按钮 + /// + /// 工具栏按钮集合 + public virtual Button[] GetToolbarButtons() + { + return new Button[0]; + } + + /// + /// 获取插件的状态栏信息 + /// + /// 状态栏信息 + public virtual string GetStatusBarInfo() + { + return $"{Name} v{Version} - {(IsEnabled ? "已启用" : "已禁用")}"; + } + + /// + /// 插件配置变更时调用 + /// + public virtual void OnConfigurationChanged() + { + LogHelper.WriteLogToFile($"插件 {Name} 配置已变更"); + } + + #region 便捷方法 + + /// + /// 显示通知消息 + /// + /// 消息内容 + /// 消息类型 + protected void ShowNotification(string message, NotificationType type = NotificationType.Info) + { + WindowService.ShowNotification(message, type); + } + + /// + /// 显示确认对话框 + /// + /// 消息内容 + /// 标题 + /// 用户选择结果 + protected bool ShowConfirmDialog(string message, string title = "确认") + { + return WindowService.ShowConfirmDialog(message, title); + } + + /// + /// 显示输入对话框 + /// + /// 提示消息 + /// 标题 + /// 默认值 + /// 用户输入内容 + protected string ShowInputDialog(string message, string title = "输入", string defaultValue = "") + { + return WindowService.ShowInputDialog(message, title, defaultValue); + } + + /// + /// 获取系统设置 + /// + /// 设置类型 + /// 设置键 + /// 默认值 + /// 设置值 + protected T GetSetting(string key, T defaultValue = default(T)) + { + return GetService.GetSetting(key, defaultValue); + } + + /// + /// 设置系统设置 + /// + /// 设置类型 + /// 设置键 + /// 设置值 + protected void SetSetting(string key, T value) + { + ActionService.SetSetting(key, value); + } + + /// + /// 保存设置 + /// + protected void SaveSettings() + { + ActionService.SaveSettings(); + } + + /// + /// 清除当前画布 + /// + protected void ClearCanvas() + { + ActionService.ClearCanvas(); + } + + /// + /// 撤销操作 + /// + protected void Undo() + { + ActionService.Undo(); + } + + /// + /// 重做操作 + /// + protected void Redo() + { + ActionService.Redo(); + } + + /// + /// 检查是否可以撤销 + /// + protected bool CanUndo => GetService.CanUndo; + + /// + /// 检查是否可以重做 + /// + protected bool CanRedo => GetService.CanRedo; + + /// + /// 获取当前绘制模式 + /// + protected int CurrentDrawingMode => GetService.CurrentDrawingMode; + + /// + /// 设置绘制模式 + /// + /// 绘制模式 + protected void SetDrawingMode(int mode) + { + ActionService.SetDrawingMode(mode); + } + + /// + /// 注册事件处理器 + /// + /// 事件名称 + /// 事件处理器 + protected void RegisterEventHandler(string eventName, System.EventHandler handler) + { + ActionService.RegisterEventHandler(eventName, handler); + } + + /// + /// 注销事件处理器 + /// + /// 事件名称 + /// 事件处理器 + protected void UnregisterEventHandler(string eventName, System.EventHandler handler) + { + ActionService.UnregisterEventHandler(eventName, handler); + } + + /// + /// 触发事件 + /// + /// 事件名称 + /// 事件发送者 + /// 事件参数 + protected void TriggerEvent(string eventName, object sender, System.EventArgs args) + { + ActionService.TriggerEvent(eventName, sender, args); + } + + #endregion + } +} \ No newline at end of file diff --git a/Ink Canvas/Helpers/Plugins/IActionService.cs b/Ink Canvas/Helpers/Plugins/IActionService.cs new file mode 100644 index 00000000..0101a605 --- /dev/null +++ b/Ink Canvas/Helpers/Plugins/IActionService.cs @@ -0,0 +1,296 @@ +using System; +using System.Windows.Media; + +namespace Ink_Canvas.Helpers.Plugins +{ + /// + /// 操作服务接口,统一所有执行操作相关的方法 + /// + public interface IActionService + { + #region 画布操作 + + /// + /// 清除当前画布 + /// + void ClearCanvas(); + + /// + /// 清除所有画布 + /// + void ClearAllCanvases(); + + /// + /// 添加新页面 + /// + void AddNewPage(); + + /// + /// 删除当前页面 + /// + void DeleteCurrentPage(); + + /// + /// 切换到指定页面 + /// + /// 页面索引 + void SwitchToPage(int pageIndex); + + /// + /// 切换到下一页 + /// + void NextPage(); + + /// + /// 切换到上一页 + /// + void PreviousPage(); + + #endregion + + #region 绘制操作 + + /// + /// 设置绘制模式 + /// + /// 绘制模式 + void SetDrawingMode(int mode); + + /// + /// 设置笔触宽度 + /// + /// 宽度 + void SetInkWidth(double width); + + /// + /// 设置笔触颜色 + /// + /// 颜色 + void SetInkColor(Color color); + + /// + /// 设置高亮笔宽度 + /// + /// 宽度 + void SetHighlighterWidth(double width); + + /// + /// 设置橡皮擦大小 + /// + /// 大小 + void SetEraserSize(int size); + + /// + /// 设置橡皮擦类型 + /// + /// 类型 + void SetEraserType(int type); + + /// + /// 设置橡皮擦形状 + /// + /// 形状 + void SetEraserShape(int shape); + + /// + /// 设置笔触透明度 + /// + /// 透明度 + void SetInkAlpha(double alpha); + + /// + /// 设置笔触样式 + /// + /// 样式 + void SetInkStyle(int style); + + /// + /// 设置背景颜色 + /// + /// 颜色 + void SetBackgroundColor(string color); + + #endregion + + #region 文件操作 + + /// + /// 保存画布内容 + /// + /// 文件路径 + void SaveCanvas(string filePath); + + /// + /// 加载画布内容 + /// + /// 文件路径 + void LoadCanvas(string filePath); + + /// + /// 导出为图片 + /// + /// 文件路径 + /// 图片格式 + void ExportAsImage(string filePath, string format); + + /// + /// 导出为PDF + /// + /// 文件路径 + void ExportAsPDF(string filePath); + + #endregion + + #region 撤销重做操作 + + /// + /// 撤销操作 + /// + void Undo(); + + /// + /// 重做操作 + /// + void Redo(); + + #endregion + + #region 选择操作 + + /// + /// 全选 + /// + void SelectAll(); + + /// + /// 取消选择 + /// + void DeselectAll(); + + /// + /// 删除选中内容 + /// + void DeleteSelected(); + + /// + /// 复制选中内容 + /// + void CopySelected(); + + /// + /// 剪切选中内容 + /// + void CutSelected(); + + /// + /// 粘贴内容 + /// + void Paste(); + + #endregion + + #region 系统设置操作 + + /// + /// 设置系统设置 + /// + /// 设置类型 + /// 设置键 + /// 设置值 + void SetSetting(string key, T value); + + /// + /// 保存设置到文件 + /// + void SaveSettings(); + + /// + /// 从文件加载设置 + /// + void LoadSettings(); + + /// + /// 重置设置为默认值 + /// + void ResetSettings(); + + #endregion + + #region 插件管理操作 + + /// + /// 启用插件 + /// + /// 插件名称 + void EnablePlugin(string pluginName); + + /// + /// 禁用插件 + /// + /// 插件名称 + void DisablePlugin(string pluginName); + + /// + /// 卸载插件 + /// + /// 插件名称 + void UnloadPlugin(string pluginName); + + #endregion + + #region 事件系统操作 + + /// + /// 注册事件处理器 + /// + /// 事件名称 + /// 事件处理器 + void RegisterEventHandler(string eventName, EventHandler handler); + + /// + /// 注销事件处理器 + /// + /// 事件名称 + /// 事件处理器 + void UnregisterEventHandler(string eventName, EventHandler handler); + + /// + /// 触发事件 + /// + /// 事件名称 + /// 事件发送者 + /// 事件参数 + void TriggerEvent(string eventName, object sender, EventArgs args); + + #endregion + + #region 应用程序操作 + + /// + /// 重启应用程序 + /// + void RestartApplication(); + + /// + /// 退出应用程序 + /// + void ExitApplication(); + + /// + /// 检查更新 + /// + void CheckForUpdates(); + + /// + /// 打开帮助文档 + /// + void OpenHelpDocument(); + + /// + /// 打开关于页面 + /// + void OpenAboutPage(); + + #endregion + } +} \ No newline at end of file diff --git a/Ink Canvas/Helpers/Plugins/IGetService.cs b/Ink Canvas/Helpers/Plugins/IGetService.cs new file mode 100644 index 00000000..70ff947e --- /dev/null +++ b/Ink Canvas/Helpers/Plugins/IGetService.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +namespace Ink_Canvas.Helpers.Plugins +{ + /// + /// 获取服务接口,统一所有获取类的方法 + /// + public interface IGetService + { + #region 窗口和UI获取 + + /// + /// 获取主窗口引用 + /// + Window MainWindow { get; } + + /// + /// 获取当前画布 + /// + InkCanvas CurrentCanvas { get; } + + /// + /// 获取所有画布页面 + /// + List AllCanvasPages { get; } + + /// + /// 获取当前页面索引 + /// + int CurrentPageIndex { get; } + + /// + /// 获取当前页面数量 + /// + int TotalPageCount { get; } + + /// + /// 获取浮动工具栏 + /// + FrameworkElement FloatingToolBar { get; } + + /// + /// 获取左侧面板 + /// + FrameworkElement LeftPanel { get; } + + /// + /// 获取右侧面板 + /// + FrameworkElement RightPanel { get; } + + /// + /// 获取顶部面板 + /// + FrameworkElement TopPanel { get; } + + /// + /// 获取底部面板 + /// + FrameworkElement BottomPanel { get; } + + #endregion + + #region 绘制工具状态获取 + + /// + /// 获取当前绘制模式 + /// + int CurrentDrawingMode { get; } + + /// + /// 获取当前笔触宽度 + /// + double CurrentInkWidth { get; } + + /// + /// 获取当前笔触颜色 + /// + Color CurrentInkColor { get; } + + /// + /// 获取当前高亮笔宽度 + /// + double CurrentHighlighterWidth { get; } + + /// + /// 获取当前橡皮擦大小 + /// + int CurrentEraserSize { get; } + + /// + /// 获取当前橡皮擦类型 + /// + int CurrentEraserType { get; } + + /// + /// 获取当前橡皮擦形状 + /// + int CurrentEraserShape { get; } + + /// + /// 获取当前笔触透明度 + /// + double CurrentInkAlpha { get; } + + /// + /// 获取当前笔触样式 + /// + int CurrentInkStyle { get; } + + /// + /// 获取当前背景颜色 + /// + string CurrentBackgroundColor { get; } + + #endregion + + #region 应用状态获取 + + /// + /// 获取当前主题模式 + /// + bool IsDarkTheme { get; } + + /// + /// 获取当前是否为白板模式 + /// + bool IsWhiteboardMode { get; } + + /// + /// 获取当前是否为PPT模式 + /// + bool IsPPTMode { get; } + + /// + /// 获取当前是否为全屏模式 + /// + bool IsFullScreenMode { get; } + + /// + /// 获取当前是否为画板模式 + /// + bool IsCanvasMode { get; } + + /// + /// 获取当前是否为选择模式 + /// + bool IsSelectionMode { get; } + + /// + /// 获取当前是否为擦除模式 + /// + bool IsEraserMode { get; } + + /// + /// 获取当前是否为形状绘制模式 + /// + bool IsShapeDrawingMode { get; } + + /// + /// 获取当前是否为高亮模式 + /// + bool IsHighlighterMode { get; } + + #endregion + + #region 撤销重做状态获取 + + /// + /// 获取是否可以撤销 + /// + bool CanUndo { get; } + + /// + /// 获取是否可以重做 + /// + bool CanRedo { get; } + + #endregion + + #region 系统设置获取 + + /// + /// 获取系统设置 + /// + /// 设置类型 + /// 设置键 + /// 默认值 + /// 设置值 + T GetSetting(string key, T defaultValue = default(T)); + + #endregion + + #region 插件信息获取 + + /// + /// 获取所有已加载的插件 + /// + /// 插件列表 + List GetAllPlugins(); + + /// + /// 获取指定插件 + /// + /// 插件名称 + /// 插件实例 + IPlugin GetPlugin(string pluginName); + + #endregion + } +} \ No newline at end of file diff --git a/Ink Canvas/Helpers/Plugins/IPluginService.cs b/Ink Canvas/Helpers/Plugins/IPluginService.cs index ff24ec2b..b1923121 100644 --- a/Ink Canvas/Helpers/Plugins/IPluginService.cs +++ b/Ink Canvas/Helpers/Plugins/IPluginService.cs @@ -8,525 +8,12 @@ namespace Ink_Canvas.Helpers.Plugins { /// /// 插件服务接口,提供对软件内部功能的访问 + /// 继承自三个专门的服务接口:获取服务、窗口服务、操作服务 /// - public interface IPluginService + public interface IPluginService : IGetService, IWindowService, IActionService { - #region 窗口和UI访问 - - /// - /// 获取主窗口引用 - /// - Window MainWindow { get; } - - /// - /// 获取当前画布 - /// - InkCanvas CurrentCanvas { get; } - - /// - /// 获取所有画布页面 - /// - List AllCanvasPages { get; } - - /// - /// 获取当前页面索引 - /// - int CurrentPageIndex { get; } - - /// - /// 获取当前页面数量 - /// - int TotalPageCount { get; } - - /// - /// 获取浮动工具栏 - /// - FrameworkElement FloatingToolBar { get; } - - /// - /// 获取左侧面板 - /// - FrameworkElement LeftPanel { get; } - - /// - /// 获取右侧面板 - /// - FrameworkElement RightPanel { get; } - - /// - /// 获取顶部面板 - /// - FrameworkElement TopPanel { get; } - - /// - /// 获取底部面板 - /// - FrameworkElement BottomPanel { get; } - - #endregion - - #region 绘制工具状态 - - /// - /// 获取当前绘制模式 - /// - int CurrentDrawingMode { get; } - - /// - /// 获取当前笔触宽度 - /// - double CurrentInkWidth { get; } - - /// - /// 获取当前笔触颜色 - /// - Color CurrentInkColor { get; } - - /// - /// 获取当前高亮笔宽度 - /// - double CurrentHighlighterWidth { get; } - - /// - /// 获取当前橡皮擦大小 - /// - int CurrentEraserSize { get; } - - /// - /// 获取当前橡皮擦类型 - /// - int CurrentEraserType { get; } - - /// - /// 获取当前橡皮擦形状 - /// - int CurrentEraserShape { get; } - - /// - /// 获取当前笔触透明度 - /// - double CurrentInkAlpha { get; } - - /// - /// 获取当前笔触样式 - /// - int CurrentInkStyle { get; } - - /// - /// 获取当前背景颜色 - /// - string CurrentBackgroundColor { get; } - - #endregion - - #region 应用状态 - - /// - /// 获取当前主题模式 - /// - bool IsDarkTheme { get; } - - /// - /// 获取当前是否为白板模式 - /// - bool IsWhiteboardMode { get; } - - /// - /// 获取当前是否为PPT模式 - /// - bool IsPPTMode { get; } - - /// - /// 获取当前是否为全屏模式 - /// - bool IsFullScreenMode { get; } - - /// - /// 获取当前是否为画板模式 - /// - bool IsCanvasMode { get; } - - /// - /// 获取当前是否为选择模式 - /// - bool IsSelectionMode { get; } - - /// - /// 获取当前是否为擦除模式 - /// - bool IsEraserMode { get; } - - /// - /// 获取当前是否为形状绘制模式 - /// - bool IsShapeDrawingMode { get; } - - /// - /// 获取当前是否为高亮模式 - /// - bool IsHighlighterMode { get; } - - #endregion - - #region 画布操作 - - /// - /// 清除当前画布 - /// - void ClearCanvas(); - - /// - /// 清除所有画布 - /// - void ClearAllCanvases(); - - /// - /// 添加新页面 - /// - void AddNewPage(); - - /// - /// 删除当前页面 - /// - void DeleteCurrentPage(); - - /// - /// 切换到指定页面 - /// - /// 页面索引 - void SwitchToPage(int pageIndex); - - /// - /// 切换到下一页 - /// - void NextPage(); - - /// - /// 切换到上一页 - /// - void PreviousPage(); - - #endregion - - #region 绘制操作 - - /// - /// 设置绘制模式 - /// - /// 绘制模式 - void SetDrawingMode(int mode); - - /// - /// 设置笔触宽度 - /// - /// 宽度 - void SetInkWidth(double width); - - /// - /// 设置笔触颜色 - /// - /// 颜色 - void SetInkColor(Color color); - - /// - /// 设置高亮笔宽度 - /// - /// 宽度 - void SetHighlighterWidth(double width); - - /// - /// 设置橡皮擦大小 - /// - /// 大小 - void SetEraserSize(int size); - - /// - /// 设置橡皮擦类型 - /// - /// 类型 - void SetEraserType(int type); - - /// - /// 设置橡皮擦形状 - /// - /// 形状 - void SetEraserShape(int shape); - - /// - /// 设置笔触透明度 - /// - /// 透明度 - void SetInkAlpha(double alpha); - - /// - /// 设置笔触样式 - /// - /// 样式 - void SetInkStyle(int style); - - /// - /// 设置背景颜色 - /// - /// 颜色 - void SetBackgroundColor(string color); - - #endregion - - #region 文件操作 - - /// - /// 保存画布内容 - /// - /// 文件路径 - void SaveCanvas(string filePath); - - /// - /// 加载画布内容 - /// - /// 文件路径 - void LoadCanvas(string filePath); - - /// - /// 导出为图片 - /// - /// 文件路径 - /// 图片格式 - void ExportAsImage(string filePath, string format); - - /// - /// 导出为PDF - /// - /// 文件路径 - void ExportAsPDF(string filePath); - - #endregion - - #region 撤销重做 - - /// - /// 撤销操作 - /// - void Undo(); - - /// - /// 重做操作 - /// - void Redo(); - - /// - /// 是否可以撤销 - /// - bool CanUndo { get; } - - /// - /// 是否可以重做 - /// - bool CanRedo { get; } - - #endregion - - #region 选择操作 - - /// - /// 全选 - /// - void SelectAll(); - - /// - /// 取消选择 - /// - void DeselectAll(); - - /// - /// 删除选中内容 - /// - void DeleteSelected(); - - /// - /// 复制选中内容 - /// - void CopySelected(); - - /// - /// 剪切选中内容 - /// - void CutSelected(); - - /// - /// 粘贴内容 - /// - void Paste(); - - #endregion - - #region 窗口管理 - - /// - /// 显示设置窗口 - /// - void ShowSettingsWindow(); - - /// - /// 隐藏设置窗口 - /// - void HideSettingsWindow(); - - /// - /// 显示插件设置窗口 - /// - void ShowPluginSettingsWindow(); - - /// - /// 隐藏插件设置窗口 - /// - void HidePluginSettingsWindow(); - - /// - /// 显示帮助窗口 - /// - void ShowHelpWindow(); - - /// - /// 隐藏帮助窗口 - /// - void HideHelpWindow(); - - /// - /// 显示关于窗口 - /// - void ShowAboutWindow(); - - /// - /// 隐藏关于窗口 - /// - void HideAboutWindow(); - - #endregion - - #region 通知和消息 - - /// - /// 显示通知消息 - /// - /// 消息内容 - /// 消息类型 - void ShowNotification(string message, NotificationType type = NotificationType.Info); - - /// - /// 显示确认对话框 - /// - /// 消息内容 - /// 标题 - /// 用户选择结果 - bool ShowConfirmDialog(string message, string title = "确认"); - - /// - /// 显示输入对话框 - /// - /// 提示消息 - /// 标题 - /// 默认值 - /// 用户输入内容 - string ShowInputDialog(string message, string title = "输入", string defaultValue = ""); - - #endregion - - #region 系统功能 - - /// - /// 获取系统设置 - /// - /// 设置类型 - /// 设置键 - /// 默认值 - /// 设置值 - T GetSetting(string key, T defaultValue = default(T)); - - /// - /// 设置系统设置 - /// - /// 设置类型 - /// 设置键 - /// 设置值 - void SetSetting(string key, T value); - - /// - /// 保存设置到文件 - /// - void SaveSettings(); - - /// - /// 从文件加载设置 - /// - void LoadSettings(); - - /// - /// 重置设置为默认值 - /// - void ResetSettings(); - - #endregion - - #region 插件管理 - - /// - /// 获取所有已加载的插件 - /// - /// 插件列表 - List GetAllPlugins(); - - /// - /// 获取指定插件 - /// - /// 插件名称 - /// 插件实例 - IPlugin GetPlugin(string pluginName); - - /// - /// 启用插件 - /// - /// 插件名称 - void EnablePlugin(string pluginName); - - /// - /// 禁用插件 - /// - /// 插件名称 - void DisablePlugin(string pluginName); - - /// - /// 卸载插件 - /// - /// 插件名称 - void UnloadPlugin(string pluginName); - - #endregion - - #region 事件系统 - - /// - /// 注册事件处理器 - /// - /// 事件名称 - /// 事件处理器 - void RegisterEventHandler(string eventName, EventHandler handler); - - /// - /// 注销事件处理器 - /// - /// 事件名称 - /// 事件处理器 - void UnregisterEventHandler(string eventName, EventHandler handler); - - /// - /// 触发事件 - /// - /// 事件名称 - /// 事件发送者 - /// 事件参数 - void TriggerEvent(string eventName, object sender, EventArgs args); - - #endregion + // 这个接口现在继承自三个专门的服务接口 + // 所有方法都在子接口中定义,这里不需要重复定义 } /// diff --git a/Ink Canvas/Helpers/Plugins/IWindowService.cs b/Ink Canvas/Helpers/Plugins/IWindowService.cs new file mode 100644 index 00000000..2685046c --- /dev/null +++ b/Ink Canvas/Helpers/Plugins/IWindowService.cs @@ -0,0 +1,154 @@ +using System; + +namespace Ink_Canvas.Helpers.Plugins +{ + /// + /// 窗口服务接口,统一所有窗口操作相关的方法 + /// + public interface IWindowService + { + #region 窗口显示和隐藏 + + /// + /// 显示设置窗口 + /// + void ShowSettingsWindow(); + + /// + /// 隐藏设置窗口 + /// + void HideSettingsWindow(); + + /// + /// 显示插件设置窗口 + /// + void ShowPluginSettingsWindow(); + + /// + /// 隐藏插件设置窗口 + /// + void HidePluginSettingsWindow(); + + /// + /// 显示帮助窗口 + /// + void ShowHelpWindow(); + + /// + /// 隐藏帮助窗口 + /// + void HideHelpWindow(); + + /// + /// 显示关于窗口 + /// + void ShowAboutWindow(); + + /// + /// 隐藏关于窗口 + /// + void HideAboutWindow(); + + #endregion + + #region 对话框和通知 + + /// + /// 显示通知消息 + /// + /// 消息内容 + /// 消息类型 + void ShowNotification(string message, NotificationType type = NotificationType.Info); + + /// + /// 显示确认对话框 + /// + /// 消息内容 + /// 标题 + /// 用户选择结果 + bool ShowConfirmDialog(string message, string title = "确认"); + + /// + /// 显示输入对话框 + /// + /// 提示消息 + /// 标题 + /// 默认值 + /// 用户输入内容 + string ShowInputDialog(string message, string title = "输入", string defaultValue = ""); + + #endregion + + #region 窗口状态控制 + + /// + /// 设置窗口全屏状态 + /// + /// 是否全屏 + void SetFullScreen(bool isFullScreen); + + /// + /// 设置窗口置顶状态 + /// + /// 是否置顶 + void SetTopMost(bool isTopMost); + + /// + /// 设置窗口可见性 + /// + /// 是否可见 + void SetWindowVisibility(bool isVisible); + + /// + /// 最小化窗口 + /// + void MinimizeWindow(); + + /// + /// 最大化窗口 + /// + void MaximizeWindow(); + + /// + /// 恢复窗口 + /// + void RestoreWindow(); + + /// + /// 关闭窗口 + /// + void CloseWindow(); + + #endregion + + #region 窗口位置和大小 + + /// + /// 设置窗口位置 + /// + /// X坐标 + /// Y坐标 + void SetWindowPosition(double x, double y); + + /// + /// 设置窗口大小 + /// + /// 宽度 + /// 高度 + void SetWindowSize(double width, double height); + + /// + /// 获取窗口位置 + /// + /// 窗口位置 + (double x, double y) GetWindowPosition(); + + /// + /// 获取窗口大小 + /// + /// 窗口大小 + (double width, double height) GetWindowSize(); + + #endregion + } +} \ No newline at end of file diff --git a/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs b/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs index 3f7ec460..9975998e 100644 --- a/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs +++ b/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs @@ -115,7 +115,149 @@ namespace Ink_Canvas.Helpers.Plugins #endregion - #region 画布操作 + #region IGetService 实现 + + public bool CanUndo => false; // 暂时返回默认值 + + public bool CanRedo => false; // 暂时返回默认值 + + public T GetSetting(string key, T defaultValue = default(T)) + { + // 暂时不实现,避免访问权限问题 + return defaultValue; + } + + public List GetAllPlugins() + { + return new List(PluginManager.Instance.Plugins); + } + + public IPlugin GetPlugin(string pluginName) + { + return PluginManager.Instance.Plugins.FirstOrDefault(p => p.Name == pluginName); + } + + #endregion + + #region IWindowService 实现 + + public void ShowSettingsWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void HideSettingsWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void ShowPluginSettingsWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void HidePluginSettingsWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void ShowHelpWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void HideHelpWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void ShowAboutWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void HideAboutWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void ShowNotification(string message, NotificationType type = NotificationType.Info) + { + // 暂时不实现,避免访问权限问题 + } + + public bool ShowConfirmDialog(string message, string title = "确认") + { + // 暂时不实现,避免访问权限问题 + return false; + } + + public string ShowInputDialog(string message, string title = "输入", string defaultValue = "") + { + // 暂时不实现,避免访问权限问题 + return defaultValue; + } + + public void SetFullScreen(bool isFullScreen) + { + // 暂时不实现,避免访问权限问题 + } + + public void SetTopMost(bool isTopMost) + { + // 暂时不实现,避免访问权限问题 + } + + public void SetWindowVisibility(bool isVisible) + { + // 暂时不实现,避免访问权限问题 + } + + public void MinimizeWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void MaximizeWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void RestoreWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void CloseWindow() + { + // 暂时不实现,避免访问权限问题 + } + + public void SetWindowPosition(double x, double y) + { + // 暂时不实现,避免访问权限问题 + } + + public void SetWindowSize(double width, double height) + { + // 暂时不实现,避免访问权限问题 + } + + public (double x, double y) GetWindowPosition() + { + // 暂时不实现,避免访问权限问题 + return (0, 0); + } + + public (double width, double height) GetWindowSize() + { + // 暂时不实现,避免访问权限问题 + return (800, 600); + } + + #endregion + + #region IActionService 实现 public void ClearCanvas() { @@ -152,10 +294,6 @@ namespace Ink_Canvas.Helpers.Plugins // 暂时不实现,避免访问权限问题 } - #endregion - - #region 绘制操作 - public void SetDrawingMode(int mode) { // 暂时不实现,避免访问权限问题 @@ -206,10 +344,6 @@ namespace Ink_Canvas.Helpers.Plugins // 暂时不实现,避免访问权限问题 } - #endregion - - #region 文件操作 - public void SaveCanvas(string filePath) { // 暂时不实现,避免访问权限问题 @@ -230,10 +364,6 @@ namespace Ink_Canvas.Helpers.Plugins // 暂时不实现,避免访问权限问题 } - #endregion - - #region 撤销重做 - public void Undo() { // 暂时不实现,避免访问权限问题 @@ -244,14 +374,6 @@ namespace Ink_Canvas.Helpers.Plugins // 暂时不实现,避免访问权限问题 } - public bool CanUndo => false; // 暂时返回默认值 - - public bool CanRedo => false; // 暂时返回默认值 - - #endregion - - #region 选择操作 - public void SelectAll() { // 暂时不实现,避免访问权限问题 @@ -282,81 +404,6 @@ namespace Ink_Canvas.Helpers.Plugins // 暂时不实现,避免访问权限问题 } - #endregion - - #region 窗口管理 - - public void ShowSettingsWindow() - { - // 暂时不实现,避免访问权限问题 - } - - public void HideSettingsWindow() - { - // 暂时不实现,避免访问权限问题 - } - - public void ShowPluginSettingsWindow() - { - // 暂时不实现,避免访问权限问题 - } - - public void HidePluginSettingsWindow() - { - // 暂时不实现,避免访问权限问题 - } - - public void ShowHelpWindow() - { - // 暂时不实现,避免访问权限问题 - } - - public void HideHelpWindow() - { - // 暂时不实现,避免访问权限问题 - } - - public void ShowAboutWindow() - { - // 暂时不实现,避免访问权限问题 - } - - public void HideAboutWindow() - { - // 暂时不实现,避免访问权限问题 - } - - #endregion - - #region 通知和消息 - - public void ShowNotification(string message, NotificationType type = NotificationType.Info) - { - // 暂时不实现,避免访问权限问题 - } - - public bool ShowConfirmDialog(string message, string title = "确认") - { - // 暂时不实现,避免访问权限问题 - return false; - } - - public string ShowInputDialog(string message, string title = "输入", string defaultValue = "") - { - // 暂时不实现,避免访问权限问题 - return defaultValue; - } - - #endregion - - #region 系统功能 - - public T GetSetting(string key, T defaultValue = default(T)) - { - // 暂时不实现,避免访问权限问题 - return defaultValue; - } - public void SetSetting(string key, T value) { // 暂时不实现,避免访问权限问题 @@ -377,20 +424,6 @@ namespace Ink_Canvas.Helpers.Plugins // 暂时不实现,避免访问权限问题 } - #endregion - - #region 插件管理 - - public List GetAllPlugins() - { - return new List(PluginManager.Instance.Plugins); - } - - public IPlugin GetPlugin(string pluginName) - { - return PluginManager.Instance.Plugins.FirstOrDefault(p => p.Name == pluginName); - } - public void EnablePlugin(string pluginName) { var plugin = GetPlugin(pluginName); @@ -418,10 +451,6 @@ namespace Ink_Canvas.Helpers.Plugins } } - #endregion - - #region 事件系统 - public void RegisterEventHandler(string eventName, EventHandler handler) { if (!_eventHandlers.ContainsKey(eventName)) @@ -450,6 +479,31 @@ namespace Ink_Canvas.Helpers.Plugins } } + public void RestartApplication() + { + // 暂时不实现,避免访问权限问题 + } + + public void ExitApplication() + { + // 暂时不实现,避免访问权限问题 + } + + public void CheckForUpdates() + { + // 暂时不实现,避免访问权限问题 + } + + public void OpenHelpDocument() + { + // 暂时不实现,避免访问权限问题 + } + + public void OpenAboutPage() + { + // 暂时不实现,避免访问权限问题 + } + #endregion } } \ No newline at end of file From edb206ffa5914b97ac7f892386027ef73458bc77 Mon Sep 17 00:00:00 2001 From: CJKmkp <2564608840@qq.com> Date: Sun, 31 Aug 2025 15:35:28 +0800 Subject: [PATCH 02/50] =?UTF-8?q?add:=E6=96=B0=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Ink Canvas/InkCanvasForClass.csproj | 9 +- Ink Canvas/MainWindow.xaml | 15 + Ink Canvas/MainWindow.xaml.cs | 16 + .../SettingsViews/AboutPanel.xaml | 191 + .../SettingsViews/AboutPanel.xaml.cs | 243 ++ .../SettingsViews/AppearancePanel.xaml | 12 + .../SettingsViews/AppearancePanel.xaml.cs | 76 + .../FloatingBarDnDSettingsPanel.xaml | 98 + .../FloatingBarDnDSettingsPanel.xaml.cs | 128 + .../SettingsViews/SettingsBaseView.xaml | 54 + .../SettingsViews/SettingsBaseView.xaml.cs | 184 + .../Windows/SettingsViews/SettingsWindow.xaml | 3273 +++++++++++++++++ .../SettingsViews/SettingsWindow.xaml.cs | 325 ++ ...vasForClass.csproj.AssemblyReference.cache | Bin 35374 -> 35826 bytes 14 files changed, 4618 insertions(+), 6 deletions(-) create mode 100644 Ink Canvas/Windows/SettingsViews/SettingsViews/AboutPanel.xaml create mode 100644 Ink Canvas/Windows/SettingsViews/SettingsViews/AboutPanel.xaml.cs create mode 100644 Ink Canvas/Windows/SettingsViews/SettingsViews/AppearancePanel.xaml create mode 100644 Ink Canvas/Windows/SettingsViews/SettingsViews/AppearancePanel.xaml.cs create mode 100644 Ink Canvas/Windows/SettingsViews/SettingsViews/FloatingBarDnDSettingsPanel.xaml create mode 100644 Ink Canvas/Windows/SettingsViews/SettingsViews/FloatingBarDnDSettingsPanel.xaml.cs create mode 100644 Ink Canvas/Windows/SettingsViews/SettingsViews/SettingsBaseView.xaml create mode 100644 Ink Canvas/Windows/SettingsViews/SettingsViews/SettingsBaseView.xaml.cs create mode 100644 Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml create mode 100644 Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs diff --git a/Ink Canvas/InkCanvasForClass.csproj b/Ink Canvas/InkCanvasForClass.csproj index 4c53cecb..2bf113a3 100644 --- a/Ink Canvas/InkCanvasForClass.csproj +++ b/Ink Canvas/InkCanvasForClass.csproj @@ -24,12 +24,8 @@ false False true - Debug;Release;x86 Debug - - - embedded - bin\$(Configuration)\ - True + Release;x86 Debug;Debug + AnyCPU;x86 embedded @@ -128,6 +124,7 @@ + diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml index 42bc95ac..98f6a1a7 100644 --- a/Ink Canvas/MainWindow.xaml +++ b/Ink Canvas/MainWindow.xaml @@ -531,6 +531,21 @@ + + + + + + + 打开新的设置窗口,提供更丰富的设置选项和更好的用户体验。 + + private static void ApplyZOrder() { - // 按创建时间排序,最新的窗口在最后 - var sortedWindows = _windowStack - .Where(w => IsWindow(w.Handle) && IsWindowVisible(w.Handle) && !IsIconic(w.Handle)) - .OrderBy(w => w.CreatedTime) - .ToList(); - - if (sortedWindows.Count == 0) return; - - // 获取主窗口(第一个注册的窗口) - var mainWindow = sortedWindows.FirstOrDefault(); - if (mainWindow == null) return; - - // 如果主窗口需要置顶且启用了无焦点模式 - if (mainWindow.IsTopmost && mainWindow.IsNoFocusMode) + // 简化逻辑:直接设置所有窗口为置顶,让Windows系统自然处理层级 + foreach (var windowInfo in _windowStack.ToList()) { - // 检查是否有子窗口在前景 - var foregroundWindow = GetForegroundWindow(); - var hasChildWindowInForeground = false; - - if (foregroundWindow != mainWindow.Handle) - { - var foregroundWindowProcessId = GetWindowThreadProcessId(foregroundWindow, out uint processId); - var currentProcessId = GetCurrentProcessId(); - - if (processId == currentProcessId) - { - // 检查前景窗口是否在我们的窗口列表中 - var foregroundWindowInfo = sortedWindows.FirstOrDefault(w => w.Handle == foregroundWindow); - if (foregroundWindowInfo != null) - { - hasChildWindowInForeground = true; - } - } - } - - if (!hasChildWindowInForeground) - { - // 没有子窗口在前景,主窗口置顶 - SetWindowPos(mainWindow.Handle, HWND_TOPMOST, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER); - - // 确保主窗口样式正确 - int exStyle = GetWindowLong(mainWindow.Handle, GWL_EXSTYLE); - if ((exStyle & WS_EX_TOPMOST) == 0) - { - SetWindowLong(mainWindow.Handle, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST); - } - } - } - - // 处理其他窗口的层级 - for (int i = 1; i < sortedWindows.Count; i++) - { - var windowInfo = sortedWindows[i]; - - // 子窗口应该置顶于主窗口 - if (windowInfo.IsTopmost) + if (windowInfo.IsTopmost && IsWindow(windowInfo.Handle) && IsWindowVisible(windowInfo.Handle) && !IsIconic(windowInfo.Handle)) { + // 设置窗口为置顶 SetWindowPos(windowInfo.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER); @@ -273,5 +237,28 @@ namespace Ink_Canvas.Helpers return _windowStack.Count; } } + + /// + /// 强制刷新所有窗口的置顶状态 + /// + public static void ForceRefreshAllWindows() + { + lock (_lockObject) + { + foreach (var windowInfo in _windowStack.ToList()) + { + if (windowInfo.IsTopmost && IsWindow(windowInfo.Handle)) + { + // 强制设置窗口为置顶 + SetWindowPos(windowInfo.Handle, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER); + + // 确保窗口样式正确 + int exStyle = GetWindowLong(windowInfo.Handle, GWL_EXSTYLE); + SetWindowLong(windowInfo.Handle, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST); + } + } + } + } } } \ No newline at end of file diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs index 54fdb76b..aa566704 100644 --- a/Ink Canvas/MainWindow.xaml.cs +++ b/Ink Canvas/MainWindow.xaml.cs @@ -16,6 +16,7 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; +using System.Windows.Controls.Primitives; using System.Windows.Forms; using System.Windows.Ink; using System.Windows.Input; @@ -246,6 +247,9 @@ namespace Ink_Canvas // 为浮动栏按钮添加触摸事件支持 AddTouchSupportToFloatingBarButtons(); + + // 为滑块控件添加触摸事件支持 + AddTouchSupportToSliders(); } @@ -1755,6 +1759,9 @@ namespace Ink_Canvas // 先设置WPF的Topmost属性 Topmost = true; + // 立即应用置顶 + WindowZOrderManager.BringToTop(this); + // 如果启用了无焦点模式,需要特殊处理 if (Settings.Advanced.IsNoFocusMode) { @@ -1847,8 +1854,8 @@ namespace Ink_Canvas // 检查是否有子窗口在前景 if (!WindowZOrderManager.HasChildWindowInForeground()) { - // 没有子窗口在前景,重新应用Z-Order - WindowZOrderManager.SetWindowTopmost(this, true); + // 没有子窗口在前景,强制刷新所有窗口的置顶状态 + WindowZOrderManager.ForceRefreshAllWindows(); } } catch (Exception ex) @@ -2227,5 +2234,288 @@ namespace Ink_Canvas LogHelper.WriteLogToFile($"设置工具模式时出错: {ex.Message}", LogHelper.LogType.Error); } } + + #region 滑块触摸支持 + + /// + /// 为所有滑块控件添加触摸和手写笔事件支持 + /// + private void AddTouchSupportToSliders() + { + try + { + // 获取所有滑块控件并添加触摸支持 + var sliders = new List + { + InkFadeTimeSlider, + AutoStraightenLineThresholdSlider, + LineStraightenSensitivitySlider, + LineEndpointSnappingThresholdSlider, + ViewboxFloatingBarScaleTransformValueSlider, + ViewboxFloatingBarOpacityValueSlider, + ViewboxFloatingBarOpacityInPPTValueSlider, + PPTButtonLeftPositionValueSlider, + PPTButtonRightPositionValueSlider, + PPTButtonLBPositionValueSlider, + PPTButtonRBPositionValueSlider, + TouchMultiplierSlider, + NibModeBoundsWidthSlider, + FingerModeBoundsWidthSlider, + SideControlMinimumAutomationSlider, + RandWindowOnceCloseLatencySlider, + RandWindowOnceMaxStudentsSlider, + BoardInkWidthSlider, + BoardInkAlphaSlider, + BoardHighlighterWidthSlider, + InkWidthSlider, + InkAlphaSlider, + HighlighterWidthSlider + }; + + foreach (var slider in sliders) + { + if (slider != null) + { + AddTouchSupportToSlider(slider); + } + } + + LogHelper.WriteLogToFile("已为所有滑块控件添加触摸支持", LogHelper.LogType.Trace); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"添加滑块触摸支持时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + /// + /// 为单个滑块控件添加触摸和手写笔事件支持 + /// + /// 要添加触摸支持的滑块控件 + private void AddTouchSupportToSlider(Slider slider) + { + if (slider == null) return; + + // 启用触摸和手写笔支持 + slider.IsManipulationEnabled = true; + + // 添加触摸事件 + slider.TouchDown += Slider_TouchDown; + slider.TouchMove += Slider_TouchMove; + slider.TouchUp += Slider_TouchUp; + + // 添加手写笔事件 + slider.StylusDown += Slider_StylusDown; + slider.StylusMove += Slider_StylusMove; + slider.StylusUp += Slider_StylusUp; + + // 添加操作事件(用于更精确的触摸控制) + slider.ManipulationStarted += Slider_ManipulationStarted; + slider.ManipulationDelta += Slider_ManipulationDelta; + slider.ManipulationCompleted += Slider_ManipulationCompleted; + } + + /// + /// 滑块触摸按下事件处理 + /// + private void Slider_TouchDown(object sender, TouchEventArgs e) + { + var slider = sender as Slider; + if (slider == null) return; + + // 捕获触摸设备 + slider.CaptureTouch(e.TouchDevice); + + // 计算触摸位置对应的滑块值 + var touchPoint = e.GetTouchPoint(slider); + UpdateSliderValueFromPosition(slider, touchPoint.Position); + + e.Handled = true; + } + + /// + /// 滑块触摸移动事件处理 + /// + private void Slider_TouchMove(object sender, TouchEventArgs e) + { + var slider = sender as Slider; + if (slider == null) return; + + // 计算触摸位置对应的滑块值 + var touchPoint = e.GetTouchPoint(slider); + UpdateSliderValueFromPosition(slider, touchPoint.Position); + + e.Handled = true; + } + + /// + /// 滑块触摸释放事件处理 + /// + private void Slider_TouchUp(object sender, TouchEventArgs e) + { + var slider = sender as Slider; + if (slider == null) return; + + // 释放触摸捕获 + slider.ReleaseTouchCapture(e.TouchDevice); + + e.Handled = true; + } + + /// + /// 滑块手写笔按下事件处理 + /// + private void Slider_StylusDown(object sender, StylusDownEventArgs e) + { + var slider = sender as Slider; + if (slider == null) return; + + // 捕获手写笔设备 + slider.CaptureStylus(); + + // 计算手写笔位置对应的滑块值 + var stylusPoint = e.GetStylusPoints(slider); + if (stylusPoint.Count > 0) + { + UpdateSliderValueFromPosition(slider, stylusPoint[0].ToPoint()); + } + + e.Handled = true; + } + + /// + /// 滑块手写笔移动事件处理 + /// + private void Slider_StylusMove(object sender, StylusEventArgs e) + { + var slider = sender as Slider; + if (slider == null || !slider.IsStylusCaptured) return; + + // 计算手写笔位置对应的滑块值 + var stylusPoint = e.GetStylusPoints(slider); + if (stylusPoint.Count > 0) + { + UpdateSliderValueFromPosition(slider, stylusPoint[0].ToPoint()); + } + + e.Handled = true; + } + + /// + /// 滑块手写笔释放事件处理 + /// + private void Slider_StylusUp(object sender, StylusEventArgs e) + { + var slider = sender as Slider; + if (slider == null) return; + + // 释放手写笔捕获 + slider.ReleaseStylusCapture(); + + e.Handled = true; + } + + /// + /// 滑块操作开始事件处理 + /// + private void Slider_ManipulationStarted(object sender, ManipulationStartedEventArgs e) + { + var slider = sender as Slider; + if (slider == null) return; + + e.Handled = true; + } + + /// + /// 滑块操作变化事件处理 + /// + private void Slider_ManipulationDelta(object sender, ManipulationDeltaEventArgs e) + { + var slider = sender as Slider; + if (slider == null) return; + + // 计算操作位置对应的滑块值 + var manipulationOrigin = e.ManipulationOrigin; + UpdateSliderValueFromPosition(slider, manipulationOrigin); + + e.Handled = true; + } + + /// + /// 滑块操作完成事件处理 + /// + private void Slider_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) + { + var slider = sender as Slider; + if (slider == null) return; + + e.Handled = true; + } + + /// + /// 根据触摸/手写笔位置更新滑块值 + /// + /// 滑块控件 + /// 触摸/手写笔位置 + private void UpdateSliderValueFromPosition(Slider slider, Point position) + { + if (slider == null) return; + + try + { + // 计算滑块轨道的位置和长度 + var track = slider.Template.FindName("PART_Track", slider) as Track; + if (track == null) return; + + var thumb = track.Thumb; + if (thumb == null) return; + + // 获取滑块轨道的实际渲染位置 + track.Arrange(new Rect(track.DesiredSize)); + thumb.Arrange(new Rect(thumb.DesiredSize)); + + // 计算相对位置(0-1之间) + double relativePosition = 0; + + if (slider.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + // 水平滑块 + var trackWidth = track.ActualWidth; + if (trackWidth > 0) + { + relativePosition = Math.Max(0, Math.Min(1, position.X / trackWidth)); + } + } + else + { + // 垂直滑块 + var trackHeight = track.ActualHeight; + if (trackHeight > 0) + { + relativePosition = Math.Max(0, Math.Min(1, position.Y / trackHeight)); + } + } + + // 计算新的滑块值 + var newValue = slider.Minimum + relativePosition * (slider.Maximum - slider.Minimum); + + // 如果启用了吸附到刻度,则调整到最近的刻度 + if (slider.IsSnapToTickEnabled && slider.TickFrequency > 0) + { + var tickCount = (int)((slider.Maximum - slider.Minimum) / slider.TickFrequency); + var tickIndex = (int)Math.Round(relativePosition * tickCount); + newValue = slider.Minimum + tickIndex * slider.TickFrequency; + } + + // 更新滑块值 + slider.Value = Math.Max(slider.Minimum, Math.Min(slider.Maximum, newValue)); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"更新滑块值时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + #endregion } } diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs index 3d6aeb34..a2dfdaa1 100644 --- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs +++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs @@ -944,7 +944,11 @@ namespace Ink_Canvas AnimationsHelper.HideWithSlideAndFade(BoardBorderTools); AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel); - new RandWindow(Settings).Show(); + var randWindow = new RandWindow(Settings); + randWindow.Show(); + // 确保窗口显示后立即置顶 + randWindow.Activate(); + WindowZOrderManager.BringToTop(randWindow); } public void CheckEraserTypeTab() diff --git a/Ink Canvas/Windows/RandWindow.xaml.cs b/Ink Canvas/Windows/RandWindow.xaml.cs index be2f2194..d62a36d8 100644 --- a/Ink Canvas/Windows/RandWindow.xaml.cs +++ b/Ink Canvas/Windows/RandWindow.xaml.cs @@ -35,6 +35,9 @@ namespace Ink_Canvas // 添加窗口关闭事件处理 Closed += RandWindow_Closed; + + // 添加窗口显示事件处理 + Loaded += RandWindow_Loaded; } private void LoadBackground(Settings settings) @@ -86,6 +89,9 @@ namespace Ink_Canvas // 添加窗口关闭事件处理 Closed += RandWindow_Closed; + + // 添加窗口显示事件处理 + Loaded += RandWindow_Loaded; new Thread(() => { @@ -349,6 +355,15 @@ namespace Ink_Canvas } } + /// + /// 窗口加载事件处理 + /// + private void RandWindow_Loaded(object sender, RoutedEventArgs e) + { + // 窗口加载完成后,立即将其置顶 + WindowZOrderManager.BringToTop(this); + } + /// /// 窗口关闭事件处理 /// diff --git a/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs b/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs index d74e4181..eea8efeb 100644 --- a/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs +++ b/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs @@ -218,6 +218,9 @@ namespace Ink_Canvas.Windows { _selectedSidebarItemName = "CanvasAndInkItem"; UpdateSidebarItemsSelection(); + + // 为自定义滑块控件添加触摸支持 + AddTouchSupportToCustomSliders(); } @@ -594,5 +597,350 @@ namespace Ink_Canvas.Windows { } } } + + #region 自定义滑块触摸支持 + + /// + /// 为自定义滑块控件添加触摸和手写笔事件支持 + /// + private void AddTouchSupportToCustomSliders() + { + try + { + // 延迟执行,确保UI元素已加载 + Dispatcher.BeginInvoke(new Action(() => + { + // 查找所有自定义滑块控件并添加触摸支持 + AddTouchSupportToCustomSliderInPane(CanvasAndInkPane); + AddTouchSupportToCustomSliderInPane(ThemePane); + AddTouchSupportToCustomSliderInPane(PowerPointPane); + AddTouchSupportToCustomSliderInPane(AutomationPane); + AddTouchSupportToCustomSliderInPane(LuckyRandomPane); + AddTouchSupportToCustomSliderInPane(AdvancedPane); + }), System.Windows.Threading.DispatcherPriority.Loaded); + } + catch (Exception ex) + { + // 记录错误但不影响程序运行 + System.Diagnostics.Debug.WriteLine($"添加自定义滑块触摸支持时出错: {ex.Message}"); + } + } + + /// + /// 为指定面板中的自定义滑块控件添加触摸支持 + /// + /// 面板控件 + private void AddTouchSupportToCustomSliderInPane(Grid pane) + { + if (pane == null) return; + + // 查找面板中的所有自定义滑块控件 + var customSliders = FindCustomSlidersInPanel(pane); + + foreach (var slider in customSliders) + { + AddTouchSupportToCustomSlider(slider); + } + } + + /// + /// 在面板中查找自定义滑块控件 + /// + /// 面板控件 + /// 自定义滑块控件列表 + private List FindCustomSlidersInPanel(DependencyObject panel) + { + var customSliders = new List(); + + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(panel); i++) + { + var child = VisualTreeHelper.GetChild(panel, i); + + // 检查是否是自定义滑块控件(包含GnomeSliderThumb图片的Grid) + if (child is Grid grid) + { + var customSlider = FindCustomSliderInGrid(grid); + if (customSlider != null) + { + customSliders.Add(customSlider); + } + } + + // 递归查找子元素 + customSliders.AddRange(FindCustomSlidersInPanel(child)); + } + + return customSliders; + } + + /// + /// 在Grid中查找自定义滑块控件 + /// + /// Grid控件 + /// 自定义滑块信息 + private CustomSliderInfo FindCustomSliderInGrid(Grid grid) + { + // 查找包含GnomeSliderThumb图片的Grid + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(grid); i++) + { + var child = VisualTreeHelper.GetChild(grid, i); + + if (child is Image image && image.Source != null) + { + var sourceName = image.Source.ToString(); + if (sourceName.Contains("GnomeSliderThumb")) + { + // 找到滑块控件,创建自定义滑块信息 + var customSlider = new CustomSliderInfo + { + Container = grid, + ThumbImage = image, + TrackBorder = FindTrackBorderInGrid(grid), + ValueBorder = FindValueBorderInGrid(grid) + }; + + return customSlider; + } + } + } + + return null; + } + + /// + /// 在Grid中查找轨道Border + /// + /// Grid控件 + /// 轨道Border + private Border FindTrackBorderInGrid(Grid grid) + { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(grid); i++) + { + var child = VisualTreeHelper.GetChild(grid, i); + + if (child is Border border && border.Background != null) + { + var brush = border.Background as SolidColorBrush; + if (brush != null && brush.Color.ToString() == "#FFDEDEDE") + { + return border; + } + } + } + + return null; + } + + /// + /// 在Grid中查找值显示Border + /// + /// Grid控件 + /// 值显示Border + private Border FindValueBorderInGrid(Grid grid) + { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(grid); i++) + { + var child = VisualTreeHelper.GetChild(grid, i); + + if (child is Border border && border.Background != null) + { + var brush = border.Background as SolidColorBrush; + if (brush != null && brush.Color.ToString() == "#FF3584E4") + { + return border; + } + } + } + + return null; + } + + /// + /// 为自定义滑块控件添加触摸支持 + /// + /// 自定义滑块信息 + private void AddTouchSupportToCustomSlider(CustomSliderInfo customSlider) + { + if (customSlider?.Container == null) return; + + // 启用触摸和手写笔支持 + customSlider.Container.IsManipulationEnabled = true; + + // 添加触摸事件 + customSlider.Container.TouchDown += (s, e) => CustomSlider_TouchDown(s, e, customSlider); + customSlider.Container.TouchMove += (s, e) => CustomSlider_TouchMove(s, e, customSlider); + customSlider.Container.TouchUp += (s, e) => CustomSlider_TouchUp(s, e, customSlider); + + // 添加手写笔事件 + customSlider.Container.StylusDown += (s, e) => CustomSlider_StylusDown(s, e, customSlider); + customSlider.Container.StylusMove += (s, e) => CustomSlider_StylusMove(s, e, customSlider); + customSlider.Container.StylusUp += (s, e) => CustomSlider_StylusUp(s, e, customSlider); + + // 添加操作事件 + customSlider.Container.ManipulationStarted += (s, e) => CustomSlider_ManipulationStarted(s, e, customSlider); + customSlider.Container.ManipulationDelta += (s, e) => CustomSlider_ManipulationDelta(s, e, customSlider); + customSlider.Container.ManipulationCompleted += (s, e) => CustomSlider_ManipulationCompleted(s, e, customSlider); + } + + /// + /// 自定义滑块触摸按下事件处理 + /// + private void CustomSlider_TouchDown(object sender, TouchEventArgs e, CustomSliderInfo customSlider) + { + customSlider.Container.CaptureTouch(e.TouchDevice); + customSlider.IsTouchCaptured = true; + var touchPoint = e.GetTouchPoint(customSlider.Container); + UpdateCustomSliderValueFromPosition(customSlider, touchPoint.Position); + e.Handled = true; + } + + /// + /// 自定义滑块触摸移动事件处理 + /// + private void CustomSlider_TouchMove(object sender, TouchEventArgs e, CustomSliderInfo customSlider) + { + // 检查是否有触摸捕获 + if (!customSlider.IsTouchCaptured) return; + var touchPoint = e.GetTouchPoint(customSlider.Container); + UpdateCustomSliderValueFromPosition(customSlider, touchPoint.Position); + e.Handled = true; + } + + /// + /// 自定义滑块触摸释放事件处理 + /// + private void CustomSlider_TouchUp(object sender, TouchEventArgs e, CustomSliderInfo customSlider) + { + customSlider.Container.ReleaseTouchCapture(e.TouchDevice); + customSlider.IsTouchCaptured = false; + e.Handled = true; + } + + /// + /// 自定义滑块手写笔按下事件处理 + /// + private void CustomSlider_StylusDown(object sender, StylusDownEventArgs e, CustomSliderInfo customSlider) + { + customSlider.Container.CaptureStylus(); + var stylusPoint = e.GetStylusPoints(customSlider.Container); + if (stylusPoint.Count > 0) + { + UpdateCustomSliderValueFromPosition(customSlider, stylusPoint[0].ToPoint()); + } + e.Handled = true; + } + + /// + /// 自定义滑块手写笔移动事件处理 + /// + private void CustomSlider_StylusMove(object sender, StylusEventArgs e, CustomSliderInfo customSlider) + { + if (!customSlider.Container.IsStylusCaptured) return; + var stylusPoint = e.GetStylusPoints(customSlider.Container); + if (stylusPoint.Count > 0) + { + UpdateCustomSliderValueFromPosition(customSlider, stylusPoint[0].ToPoint()); + } + e.Handled = true; + } + + /// + /// 自定义滑块手写笔释放事件处理 + /// + private void CustomSlider_StylusUp(object sender, StylusEventArgs e, CustomSliderInfo customSlider) + { + customSlider.Container.ReleaseStylusCapture(); + e.Handled = true; + } + + /// + /// 自定义滑块操作开始事件处理 + /// + private void CustomSlider_ManipulationStarted(object sender, ManipulationStartedEventArgs e, CustomSliderInfo customSlider) + { + e.Handled = true; + } + + /// + /// 自定义滑块操作变化事件处理 + /// + private void CustomSlider_ManipulationDelta(object sender, ManipulationDeltaEventArgs e, CustomSliderInfo customSlider) + { + var manipulationOrigin = e.ManipulationOrigin; + UpdateCustomSliderValueFromPosition(customSlider, manipulationOrigin); + e.Handled = true; + } + + /// + /// 自定义滑块操作完成事件处理 + /// + private void CustomSlider_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e, CustomSliderInfo customSlider) + { + e.Handled = true; + } + + /// + /// 根据触摸/手写笔位置更新自定义滑块值 + /// + /// 自定义滑块信息 + /// 触摸/手写笔位置 + private void UpdateCustomSliderValueFromPosition(CustomSliderInfo customSlider, Point position) + { + if (customSlider?.TrackBorder == null || customSlider.ThumbImage == null) return; + + try + { + // 计算滑块轨道的实际位置和长度 + var trackWidth = customSlider.TrackBorder.ActualWidth; + if (trackWidth <= 0) return; + + // 计算相对位置(0-1之间) + var relativePosition = Math.Max(0, Math.Min(1, position.X / trackWidth)); + + // 更新滑块位置 + var thumbTransform = customSlider.ThumbImage.RenderTransform as TranslateTransform; + if (thumbTransform == null) + { + thumbTransform = new TranslateTransform(); + customSlider.ThumbImage.RenderTransform = thumbTransform; + } + + // 计算新的滑块位置 + var newX = relativePosition * trackWidth; + thumbTransform.X = newX; + + // 更新值显示Border的宽度 + if (customSlider.ValueBorder != null) + { + var valueWidth = relativePosition * trackWidth; + customSlider.ValueBorder.Width = Math.Max(0, valueWidth); + + // 调整值显示Border的位置 + var valueMargin = customSlider.ValueBorder.Margin; + customSlider.ValueBorder.Margin = new Thickness(0, valueMargin.Top, trackWidth - valueWidth, valueMargin.Bottom); + } + + // 这里可以根据需要添加值变化事件处理 + // 例如:OnCustomSliderValueChanged(customSlider, relativePosition); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"更新自定义滑块值时出错: {ex.Message}"); + } + } + + /// + /// 自定义滑块信息类 + /// + private class CustomSliderInfo + { + public Grid Container { get; set; } + public Image ThumbImage { get; set; } + public Border TrackBorder { get; set; } + public Border ValueBorder { get; set; } + public bool IsTouchCaptured { get; set; } = false; + } + + #endregion } } From 02c6caf4656197d406827200c23dfa5eea5de1b2 Mon Sep 17 00:00:00 2001 From: CJKmkp <2564608840@qq.com> Date: Sat, 6 Sep 2025 13:30:32 +0800 Subject: [PATCH 16/50] fix:issue #153 --- Ink Canvas/MainWindow.xaml.cs | 222 +++++++++--------- .../SettingsViews/SettingsWindow.xaml.cs | 11 +- 2 files changed, 116 insertions(+), 117 deletions(-) diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs index aa566704..fc40ba2b 100644 --- a/Ink Canvas/MainWindow.xaml.cs +++ b/Ink Canvas/MainWindow.xaml.cs @@ -2299,61 +2299,44 @@ namespace Ink_Canvas // 启用触摸和手写笔支持 slider.IsManipulationEnabled = true; - // 添加触摸事件 - slider.TouchDown += Slider_TouchDown; - slider.TouchMove += Slider_TouchMove; - slider.TouchUp += Slider_TouchUp; + // 添加触摸事件 - 使用更简单直接的方法 + slider.TouchDown += (s, e) => HandleSliderTouch(s, e, slider); + slider.TouchMove += (s, e) => HandleSliderTouch(s, e, slider); + slider.TouchUp += (s, e) => HandleSliderTouchEnd(s, e, slider); // 添加手写笔事件 - slider.StylusDown += Slider_StylusDown; - slider.StylusMove += Slider_StylusMove; - slider.StylusUp += Slider_StylusUp; - - // 添加操作事件(用于更精确的触摸控制) - slider.ManipulationStarted += Slider_ManipulationStarted; - slider.ManipulationDelta += Slider_ManipulationDelta; - slider.ManipulationCompleted += Slider_ManipulationCompleted; + slider.StylusDown += (s, e) => HandleSliderStylus(s, e, slider); + slider.StylusMove += (s, e) => HandleSliderStylus(s, e, slider); + slider.StylusUp += (s, e) => HandleSliderStylusEnd(s, e, slider); } /// - /// 滑块触摸按下事件处理 + /// 处理滑块触摸事件(按下和移动) /// - private void Slider_TouchDown(object sender, TouchEventArgs e) + private void HandleSliderTouch(object sender, TouchEventArgs e, Slider slider) { - var slider = sender as Slider; if (slider == null) return; // 捕获触摸设备 - slider.CaptureTouch(e.TouchDevice); - + if (e.RoutedEvent == UIElement.TouchDownEvent) + { + slider.CaptureTouch(e.TouchDevice); + } + // 计算触摸位置对应的滑块值 var touchPoint = e.GetTouchPoint(slider); - UpdateSliderValueFromPosition(slider, touchPoint.Position); + + // 使用更精确的位置计算方法 + UpdateSliderValueFromPositionImproved(slider, touchPoint.Position); e.Handled = true; } /// - /// 滑块触摸移动事件处理 + /// 处理滑块触摸结束事件 /// - private void Slider_TouchMove(object sender, TouchEventArgs e) + private void HandleSliderTouchEnd(object sender, TouchEventArgs e, Slider slider) { - var slider = sender as Slider; - if (slider == null) return; - - // 计算触摸位置对应的滑块值 - var touchPoint = e.GetTouchPoint(slider); - UpdateSliderValueFromPosition(slider, touchPoint.Position); - - e.Handled = true; - } - - /// - /// 滑块触摸释放事件处理 - /// - private void Slider_TouchUp(object sender, TouchEventArgs e) - { - var slider = sender as Slider; if (slider == null) return; // 释放触摸捕获 @@ -2363,50 +2346,33 @@ namespace Ink_Canvas } /// - /// 滑块手写笔按下事件处理 + /// 处理滑块手写笔事件(按下和移动) /// - private void Slider_StylusDown(object sender, StylusDownEventArgs e) + private void HandleSliderStylus(object sender, StylusEventArgs e, Slider slider) { - var slider = sender as Slider; if (slider == null) return; // 捕获手写笔设备 - slider.CaptureStylus(); - + if (e.RoutedEvent == UIElement.StylusDownEvent) + { + slider.CaptureStylus(); + } + // 计算手写笔位置对应的滑块值 var stylusPoint = e.GetStylusPoints(slider); if (stylusPoint.Count > 0) { - UpdateSliderValueFromPosition(slider, stylusPoint[0].ToPoint()); + UpdateSliderValueFromPositionImproved(slider, stylusPoint[0].ToPoint()); } e.Handled = true; } /// - /// 滑块手写笔移动事件处理 + /// 处理滑块手写笔结束事件 /// - private void Slider_StylusMove(object sender, StylusEventArgs e) + private void HandleSliderStylusEnd(object sender, StylusEventArgs e, Slider slider) { - var slider = sender as Slider; - if (slider == null || !slider.IsStylusCaptured) return; - - // 计算手写笔位置对应的滑块值 - var stylusPoint = e.GetStylusPoints(slider); - if (stylusPoint.Count > 0) - { - UpdateSliderValueFromPosition(slider, stylusPoint[0].ToPoint()); - } - - e.Handled = true; - } - - /// - /// 滑块手写笔释放事件处理 - /// - private void Slider_StylusUp(object sender, StylusEventArgs e) - { - var slider = sender as Slider; if (slider == null) return; // 释放手写笔捕获 @@ -2416,44 +2382,75 @@ namespace Ink_Canvas } /// - /// 滑块操作开始事件处理 + /// 根据触摸/手写笔位置更新滑块值(改进版本) /// - private void Slider_ManipulationStarted(object sender, ManipulationStartedEventArgs e) + /// 滑块控件 + /// 触摸/手写笔位置 + private void UpdateSliderValueFromPositionImproved(Slider slider, Point position) { - var slider = sender as Slider; if (slider == null) return; - e.Handled = true; + try + { + // 获取滑块的轨道元素 + var track = slider.Template.FindName("PART_Track", slider) as Track; + if (track == null) + { + // 如果找不到轨道,使用简单方法 + UpdateSliderValueFromPosition(slider, position); + return; + } + + // 获取轨道的实际边界 + var trackBounds = track.TransformToAncestor(slider).TransformBounds(new Rect(0, 0, track.ActualWidth, track.ActualHeight)); + + double relativePosition = 0; + + if (slider.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + // 水平滑块 + if (trackBounds.Width > 0) + { + // 计算相对于轨道的相对位置 + var relativeX = position.X - trackBounds.X; + relativePosition = Math.Max(0, Math.Min(1, relativeX / trackBounds.Width)); + } + } + else + { + // 垂直滑块 + if (trackBounds.Height > 0) + { + // 计算相对于轨道的相对位置 + var relativeY = position.Y - trackBounds.Y; + relativePosition = Math.Max(0, Math.Min(1, relativeY / trackBounds.Height)); + } + } + + // 计算新的滑块值 + var newValue = slider.Minimum + relativePosition * (slider.Maximum - slider.Minimum); + + // 如果启用了吸附到刻度,则调整到最近的刻度 + if (slider.IsSnapToTickEnabled && slider.TickFrequency > 0) + { + var tickCount = (int)((slider.Maximum - slider.Minimum) / slider.TickFrequency); + var tickIndex = (int)Math.Round(relativePosition * tickCount); + newValue = slider.Minimum + tickIndex * slider.TickFrequency; + } + + // 更新滑块值 + slider.Value = Math.Max(slider.Minimum, Math.Min(slider.Maximum, newValue)); + } + catch (Exception ex) + { + // 如果改进方法失败,回退到简单方法 + UpdateSliderValueFromPosition(slider, position); + LogHelper.WriteLogToFile($"更新滑块值时出错,使用回退方法: {ex.Message}", LogHelper.LogType.Error); + } } /// - /// 滑块操作变化事件处理 - /// - private void Slider_ManipulationDelta(object sender, ManipulationDeltaEventArgs e) - { - var slider = sender as Slider; - if (slider == null) return; - - // 计算操作位置对应的滑块值 - var manipulationOrigin = e.ManipulationOrigin; - UpdateSliderValueFromPosition(slider, manipulationOrigin); - - e.Handled = true; - } - - /// - /// 滑块操作完成事件处理 - /// - private void Slider_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) - { - var slider = sender as Slider; - if (slider == null) return; - - e.Handled = true; - } - - /// - /// 根据触摸/手写笔位置更新滑块值 + /// 根据触摸/手写笔位置更新滑块值(简单版本) /// /// 滑块控件 /// 触摸/手写笔位置 @@ -2463,36 +2460,33 @@ namespace Ink_Canvas try { - // 计算滑块轨道的位置和长度 - var track = slider.Template.FindName("PART_Track", slider) as Track; - if (track == null) return; - - var thumb = track.Thumb; - if (thumb == null) return; - - // 获取滑块轨道的实际渲染位置 - track.Arrange(new Rect(track.DesiredSize)); - thumb.Arrange(new Rect(thumb.DesiredSize)); - - // 计算相对位置(0-1之间) + // 使用更简单直接的方法计算滑块值 double relativePosition = 0; if (slider.Orientation == System.Windows.Controls.Orientation.Horizontal) { - // 水平滑块 - var trackWidth = track.ActualWidth; - if (trackWidth > 0) + // 水平滑块 - 使用滑块的实际宽度 + var sliderWidth = slider.ActualWidth; + if (sliderWidth > 0) { - relativePosition = Math.Max(0, Math.Min(1, position.X / trackWidth)); + // 考虑滑块的边距和拇指大小 + var thumbSize = 20; // 假设拇指大小约为20像素 + var effectiveWidth = sliderWidth - thumbSize; + var adjustedX = position.X - thumbSize / 2; + relativePosition = Math.Max(0, Math.Min(1, adjustedX / effectiveWidth)); } } else { - // 垂直滑块 - var trackHeight = track.ActualHeight; - if (trackHeight > 0) + // 垂直滑块 - 使用滑块的实际高度 + var sliderHeight = slider.ActualHeight; + if (sliderHeight > 0) { - relativePosition = Math.Max(0, Math.Min(1, position.Y / trackHeight)); + // 考虑滑块的边距和拇指大小 + var thumbSize = 20; // 假设拇指大小约为20像素 + var effectiveHeight = sliderHeight - thumbSize; + var adjustedY = position.Y - thumbSize / 2; + relativePosition = Math.Max(0, Math.Min(1, adjustedY / effectiveHeight)); } } diff --git a/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs b/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs index eea8efeb..ded95ef8 100644 --- a/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs +++ b/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs @@ -894,8 +894,13 @@ namespace Ink_Canvas.Windows { var trackWidth = customSlider.TrackBorder.ActualWidth; if (trackWidth <= 0) return; - // 计算相对位置(0-1之间) - var relativePosition = Math.Max(0, Math.Min(1, position.X / trackWidth)); + // 考虑拇指大小,计算有效轨道长度 + var thumbSize = 21; // 根据XAML中的Width="21" + var effectiveWidth = trackWidth - thumbSize; + + // 计算相对位置(0-1之间),考虑拇指大小 + var adjustedX = position.X - thumbSize / 2; + var relativePosition = Math.Max(0, Math.Min(1, adjustedX / effectiveWidth)); // 更新滑块位置 var thumbTransform = customSlider.ThumbImage.RenderTransform as TranslateTransform; @@ -906,7 +911,7 @@ namespace Ink_Canvas.Windows { } // 计算新的滑块位置 - var newX = relativePosition * trackWidth; + var newX = relativePosition * effectiveWidth; thumbTransform.X = newX; // 更新值显示Border的宽度 From 9081aea9261d03dd6cd0c9711707a1f59e4f7b1a Mon Sep 17 00:00:00 2001 From: CJKmkp <2564608840@qq.com> Date: Sat, 6 Sep 2025 13:48:44 +0800 Subject: [PATCH 17/50] =?UTF-8?q?improve:=E5=A2=A8=E8=BF=B9=E6=B8=90?= =?UTF-8?q?=E9=9A=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Ink Canvas/Helpers/InkFadeManager.cs | 158 +++++++----------- Ink Canvas/Helpers/WindowZOrderManager.cs | 47 +++--- Ink Canvas/MainWindow.xaml.cs | 56 +++++-- .../MainWindow_cs/MW_FloatingBarIcons.cs | 3 +- Ink Canvas/MainWindow_cs/MW_TrayIcon.cs | 7 +- Ink Canvas/Windows/RandWindow.xaml.cs | 27 +-- 6 files changed, 137 insertions(+), 161 deletions(-) diff --git a/Ink Canvas/Helpers/InkFadeManager.cs b/Ink Canvas/Helpers/InkFadeManager.cs index eec846ac..a13d1ea6 100644 --- a/Ink Canvas/Helpers/InkFadeManager.cs +++ b/Ink Canvas/Helpers/InkFadeManager.cs @@ -6,6 +6,7 @@ using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; +using System.Windows.Media.Effects; using System.Windows.Shapes; using System.Windows.Threading; @@ -324,6 +325,13 @@ namespace Ink_Canvas.Helpers { path.StrokeThickness = Math.Max(drawingAttribs.Width * 1.5, 20); } + + // 为高亮笔添加轻微的模糊效果,使渐隐更加自然 + path.Effect = new BlurEffect + { + Radius = 0.5, // 轻微的模糊效果 + KernelType = KernelType.Gaussian + }; } // 不设置任何变换,保持墨迹原有粗细 @@ -381,8 +389,7 @@ namespace Ink_Canvas.Helpers { try { - // 对于普通墨迹也使用连续渐隐动画 - StartContinuousFadeAnimation(visual, stroke, currentOpacity, AnimationDuration); + StartProgressiveFadeAnimation(visual, stroke, currentOpacity, AnimationDuration); } catch (Exception ex) { @@ -390,6 +397,57 @@ namespace Ink_Canvas.Helpers } } + /// + /// 统一渐隐动画 - 整个墨迹作为一个整体进行渐隐,与擦除效果一致 + /// + private void StartUnifiedFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity, int duration) + { + try + { + // 创建透明度动画,模拟擦除时的效果 + var fadeAnimation = new DoubleAnimation + { + From = currentOpacity, + To = 0.0, + Duration = TimeSpan.FromMilliseconds(duration), + EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } + }; + + // 如果是高亮笔,添加轻微的缩放效果,使渐隐更加自然 + if (stroke.DrawingAttributes.IsHighlighter) + { + // 创建轻微的缩放动画,模拟墨迹"蒸发"的效果 + var scaleAnimation = new DoubleAnimation + { + From = 1.0, + To = 0.95, // 轻微缩小,增加自然感 + Duration = TimeSpan.FromMilliseconds(duration), + EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseIn } + }; + + // 创建缩放变换 + var scaleTransform = new ScaleTransform(); + visual.RenderTransform = scaleTransform; + visual.RenderTransformOrigin = new Point(0.5, 0.5); + + // 应用缩放动画 + scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation); + scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation); + } + + // 添加动画完成事件 + fadeAnimation.Completed += (sender, e) => OnAnimationCompleted(visual, stroke); + + // 应用透明度动画 + visual.BeginAnimation(UIElement.OpacityProperty, fadeAnimation); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"统一渐隐动画失败: {ex}", LogHelper.LogType.Error); + OnAnimationCompleted(visual, stroke); + } + } + /// /// 开始高亮笔的渐隐动画 /// @@ -397,8 +455,8 @@ namespace Ink_Canvas.Helpers { try { - // 使用连续渐隐动画而不是分段动画 - StartContinuousFadeAnimation(visual, stroke, currentOpacity, (int)(AnimationDuration * 1.5)); + // 高亮笔使用统一的渐隐动画,与擦除效果一致 + StartUnifiedFadeAnimation(visual, stroke, currentOpacity, (int)(AnimationDuration * 1.2)); } catch (Exception ex) { @@ -804,98 +862,6 @@ namespace Ink_Canvas.Helpers return curve; } - /// - /// 连续渐隐动画 - 模拟橡皮擦擦除效果 - /// - private void StartContinuousFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity, int duration) - { - try - { - // 获取墨迹的边界 - var geometry = stroke.GetGeometry(); - if (geometry == null) return; - - var bounds = geometry.Bounds; - var strokeStart = stroke.StylusPoints[0].ToPoint(); - var strokeEnd = stroke.StylusPoints[stroke.StylusPoints.Count - 1].ToPoint(); - - // 计算墨迹的方向向量 - var direction = new Vector(strokeEnd.X - strokeStart.X, strokeEnd.Y - strokeStart.Y); - var length = direction.Length; - - if (length == 0) - { - // 如果墨迹没有方向(单点),使用简单渐隐 - StartSimpleFadeAnimation(visual, stroke, currentOpacity, duration); - return; - } - - // 归一化方向向量 - direction.Normalize(); - - // 创建精确的擦除动画 - 使用PathGeometry来避免变形 - CreatePreciseEraseAnimation(visual, stroke, bounds, strokeStart, strokeEnd, direction, length, duration); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"连续渐隐动画失败: {ex}", LogHelper.LogType.Error); - // 失败时回退到简单动画 - StartSimpleFadeAnimation(visual, stroke, currentOpacity, duration); - } - } - - /// - /// 创建精确的擦除动画 - 使用动态裁剪区域避免墨迹移动 - /// - private void CreatePreciseEraseAnimation(UIElement visual, Stroke stroke, Rect bounds, Point strokeStart, Point strokeEnd, Vector direction, double length, int duration) - { - try - { - // 计算擦除方向上的移动距离 - var totalDistance = Math.Sqrt(Math.Pow(strokeEnd.X - strokeStart.X, 2) + Math.Pow(strokeEnd.Y - strokeStart.Y, 2)); - - if (totalDistance == 0) - { - // 如果墨迹没有长度,使用简单渐隐 - StartSimpleFadeAnimation(visual, stroke, visual.Opacity, duration); - return; - } - - // 创建动态裁剪区域 - 从完整墨迹开始,逐渐缩小 - var clipGeometry = new RectangleGeometry - { - Rect = bounds - }; - - visual.Clip = clipGeometry; - - // 创建擦除动画 - 裁剪区域从起点向终点移动并缩小 - // 使用更自然的擦除效果:从起点开始,逐渐向终点移动 - var eraseAnimation = new RectAnimation - { - From = bounds, // 从完整边界开始 - To = new Rect(strokeEnd.X, strokeEnd.Y, 0, bounds.Height), // 到终点位置,宽度为0 - Duration = TimeSpan.FromMilliseconds(duration), - EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } - }; - - // 添加动画完成事件 - eraseAnimation.Completed += (sender, e) => - { - OnAnimationCompleted(visual, stroke); - }; - - // 开始动画 - clipGeometry.BeginAnimation(RectangleGeometry.RectProperty, eraseAnimation); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"精确擦除动画失败: {ex}", LogHelper.LogType.Error); - // 失败时回退到简单动画 - StartSimpleFadeAnimation(visual, stroke, visual.Opacity, duration); - } - } - /// /// 动画完成后的统一处理 /// diff --git a/Ink Canvas/Helpers/WindowZOrderManager.cs b/Ink Canvas/Helpers/WindowZOrderManager.cs index 898b0c06..2ce292c8 100644 --- a/Ink Canvas/Helpers/WindowZOrderManager.cs +++ b/Ink Canvas/Helpers/WindowZOrderManager.cs @@ -148,31 +148,30 @@ namespace Ink_Canvas.Helpers { if (window == null) return; - lock (_lockObject) + try { - var windowInfo = _windowStack.FirstOrDefault(w => w.Window == window); - if (windowInfo != null) - { - // 更新创建时间,使其成为最新的窗口 - windowInfo.CreatedTime = DateTime.Now; - - // 立即将窗口置顶 - var hwnd = new WindowInteropHelper(window).Handle; - if (hwnd != IntPtr.Zero) - { - SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER); - - // 确保窗口样式正确 - int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE); - if ((exStyle & WS_EX_TOPMOST) == 0) - { - SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST); - } - } - - ApplyZOrder(); - } + var hwnd = new WindowInteropHelper(window).Handle; + if (hwnd == IntPtr.Zero) return; + + // 使用更直接的方法:先激活窗口,再置顶 + window.Activate(); + window.Focus(); + + // 设置窗口为置顶 + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER); + + // 确保窗口样式正确 + int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE); + SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST); + + // 再次确保置顶 + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"BringToTop失败: {ex.Message}", LogHelper.LogType.Error); } } diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs index fc40ba2b..9cb41455 100644 --- a/Ink Canvas/MainWindow.xaml.cs +++ b/Ink Canvas/MainWindow.xaml.cs @@ -1751,18 +1751,22 @@ namespace Ink_Canvas { try { + var hwnd = new WindowInteropHelper(this).Handle; if (Settings.Advanced.IsAlwaysOnTop) { - // 注册到Z-Order管理器 - WindowZOrderManager.RegisterWindow(this, true, Settings.Advanced.IsNoFocusMode); - // 先设置WPF的Topmost属性 Topmost = true; - // 立即应用置顶 - WindowZOrderManager.BringToTop(this); + // 使用更强的Win32 API调用来确保置顶 + // 1. 设置窗口样式为置顶 + int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE); + SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST); - // 如果启用了无焦点模式,需要特殊处理 + // 2. 使用SetWindowPos确保窗口在最顶层 + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER); + + // 3. 如果启用了无焦点模式,需要特殊处理 if (Settings.Advanced.IsNoFocusMode) { // 启动置顶维护定时器 @@ -1777,9 +1781,15 @@ namespace Ink_Canvas else { // 取消置顶时 - WindowZOrderManager.SetWindowTopmost(this, false); - - // 停止置顶维护定时器 + // 1. 先使用Win32 API取消置顶 + SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER); + + // 2. 移除置顶窗口样式 + int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE); + SetWindowLong(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_TOPMOST); + + // 3. 停止置顶维护定时器 StopTopmostMaintenance(); // 注意:这里不直接设置Topmost,让其他代码根据模式决定 @@ -1848,14 +1858,30 @@ namespace Ink_Canvas return; } - // 清理无效的窗口记录 - WindowZOrderManager.CleanupInvalidWindows(); - // 检查是否有子窗口在前景 - if (!WindowZOrderManager.HasChildWindowInForeground()) + var foregroundWindow = GetForegroundWindow(); + if (foregroundWindow != hwnd) { - // 没有子窗口在前景,强制刷新所有窗口的置顶状态 - WindowZOrderManager.ForceRefreshAllWindows(); + // 检查前景窗口是否是当前应用程序的子窗口 + var foregroundWindowProcessId = GetWindowThreadProcessId(foregroundWindow, out uint processId); + var currentProcessId = GetCurrentProcessId(); + + if (processId == currentProcessId) + { + // 如果有子窗口在前景,暂停置顶维护 + return; + } + + // 如果窗口不在最顶层且没有子窗口,重新设置置顶 + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER); + + // 确保窗口样式正确 + int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE); + if ((exStyle & WS_EX_TOPMOST) == 0) + { + SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST); + } } } catch (Exception ex) diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs index a2dfdaa1..3b976f54 100644 --- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs +++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs @@ -948,7 +948,8 @@ namespace Ink_Canvas randWindow.Show(); // 确保窗口显示后立即置顶 randWindow.Activate(); - WindowZOrderManager.BringToTop(randWindow); + randWindow.Topmost = true; + randWindow.Focus(); } public void CheckEraserTypeTab() diff --git a/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs b/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs index 0b78d802..21a9de2b 100644 --- a/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs +++ b/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs @@ -30,11 +30,10 @@ namespace Ink_Canvas var mainWin = (MainWindow)Current.MainWindow; if (mainWin.IsLoaded) { - // 通知Z-Order管理器有系统菜单打开 - // 这会导致主窗口暂时取消置顶,让系统菜单能够正常显示 + // 在无焦点模式下,暂时取消主窗口置顶,让系统菜单能够正常显示 if (Ink_Canvas.MainWindow.Settings.Advanced.IsAlwaysOnTop && Ink_Canvas.MainWindow.Settings.Advanced.IsNoFocusMode) { - WindowZOrderManager.SetWindowTopmost(mainWin, false); + mainWin.Topmost = false; } // 判斷是否在收納模式中 @@ -72,7 +71,7 @@ namespace Ink_Canvas // 菜单关闭后,恢复主窗口的置顶状态 if (Ink_Canvas.MainWindow.Settings.Advanced.IsAlwaysOnTop && Ink_Canvas.MainWindow.Settings.Advanced.IsNoFocusMode) { - WindowZOrderManager.SetWindowTopmost(mainWin, true); + mainWin.Topmost = true; } } } diff --git a/Ink Canvas/Windows/RandWindow.xaml.cs b/Ink Canvas/Windows/RandWindow.xaml.cs index d62a36d8..66ecd8df 100644 --- a/Ink Canvas/Windows/RandWindow.xaml.cs +++ b/Ink Canvas/Windows/RandWindow.xaml.cs @@ -30,14 +30,11 @@ namespace Ink_Canvas // 加载背景 LoadBackground(settings); - // 注册到Z-Order管理器,确保窗口能够正确置顶 - WindowZOrderManager.RegisterWindow(this, true, false); + // 设置窗口为置顶 + Topmost = true; // 添加窗口关闭事件处理 Closed += RandWindow_Closed; - - // 添加窗口显示事件处理 - Loaded += RandWindow_Loaded; } private void LoadBackground(Settings settings) @@ -84,14 +81,11 @@ namespace Ink_Canvas // 加载背景 LoadBackground(settings); - // 注册到Z-Order管理器,确保窗口能够正确置顶 - WindowZOrderManager.RegisterWindow(this, true, false); + // 设置窗口为置顶 + Topmost = true; // 添加窗口关闭事件处理 Closed += RandWindow_Closed; - - // 添加窗口显示事件处理 - Loaded += RandWindow_Loaded; new Thread(() => { @@ -355,22 +349,13 @@ namespace Ink_Canvas } } - /// - /// 窗口加载事件处理 - /// - private void RandWindow_Loaded(object sender, RoutedEventArgs e) - { - // 窗口加载完成后,立即将其置顶 - WindowZOrderManager.BringToTop(this); - } - /// /// 窗口关闭事件处理 /// private void RandWindow_Closed(object sender, EventArgs e) { - // 从Z-Order管理器中移除窗口 - WindowZOrderManager.UnregisterWindow(this); + // 窗口关闭时的清理工作 + // 这里可以添加必要的清理代码 } } } From 67e3d5110674e29e1b89229499bc27b4ac55f2cf Mon Sep 17 00:00:00 2001 From: CJKmkp <2564608840@qq.com> Date: Sat, 6 Sep 2025 13:58:49 +0800 Subject: [PATCH 18/50] =?UTF-8?q?improve:=E7=AA=97=E5=8F=A3=E7=BD=AE?= =?UTF-8?q?=E9=A1=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Ink Canvas/Helpers/PPTManager.cs | 56 +++++++++++++++- Ink Canvas/Helpers/PPTUIManager.cs | 37 +++++++++-- .../MainWindow_cs/MW_FloatingBarIcons.cs | 57 ++++++++++++++-- Ink Canvas/MainWindow_cs/MW_Settings.cs | 22 +++++-- Ink Canvas/Windows/CountdownTimerWindow.xaml | 66 +++++-------------- Ink Canvas/Windows/OperatingGuideWindow.xaml | 2 +- Ink Canvas/Windows/RandWindow.xaml.cs | 65 ++++++++++++++++++ 7 files changed, 232 insertions(+), 73 deletions(-) diff --git a/Ink Canvas/Helpers/PPTManager.cs b/Ink Canvas/Helpers/PPTManager.cs index d8a03bd4..48fc4c70 100644 --- a/Ink Canvas/Helpers/PPTManager.cs +++ b/Ink Canvas/Helpers/PPTManager.cs @@ -70,7 +70,32 @@ namespace Ink_Canvas.Helpers try { if (PPTApplication == null || !Marshal.IsComObject(PPTApplication)) return false; - return PPTApplication.SlideShowWindows?.Count > 0; + + // 检查是否有放映窗口 + var slideShowWindows = PPTApplication.SlideShowWindows; + if (slideShowWindows == null || slideShowWindows.Count == 0) return false; + + // 验证放映窗口是否真正有效 + try + { + var slideShowWindow = slideShowWindows[1]; + if (slideShowWindow == null) return false; + + // 尝试访问放映窗口的属性来验证其有效性 + var _ = slideShowWindow.View; + return true; + } + catch (COMException comEx) + { + var hr = (uint)comEx.HResult; + if (hr == 0x8001010E || hr == 0x80004005) + { + // COM对象已失效,触发断开连接 + DisconnectFromPPT(); + } + LogHelper.WriteLogToFile($"验证PPT放映窗口失败: {comEx.Message} (HR: 0x{hr:X8})", LogHelper.LogType.Warning); + return false; + } } catch (COMException comEx) { @@ -80,10 +105,12 @@ namespace Ink_Canvas.Helpers // COM对象已失效,触发断开连接 DisconnectFromPPT(); } + LogHelper.WriteLogToFile($"检查PPT放映状态失败: {comEx.Message} (HR: 0x{hr:X8})", LogHelper.LogType.Warning); return false; } - catch + catch (Exception ex) { + LogHelper.WriteLogToFile($"检查PPT放映状态时发生意外错误: {ex}", LogHelper.LogType.Warning); return false; } } @@ -452,7 +479,30 @@ namespace Ink_Canvas.Helpers { CurrentPresentation = activePresentation; CurrentSlides = CurrentPresentation.Slides; - SlidesCount = CurrentSlides.Count; + + // 验证页数读取是否成功 + try + { + var slideCount = CurrentSlides.Count; + if (slideCount > 0) + { + SlidesCount = slideCount; + LogHelper.WriteLogToFile($"成功读取PPT页数: {slideCount}", LogHelper.LogType.Trace); + } + else + { + // 页数为0,可能是空演示文稿或读取失败 + SlidesCount = 0; + LogHelper.WriteLogToFile("PPT演示文稿页数为0,可能为空演示文稿", LogHelper.LogType.Warning); + } + } + catch (COMException comEx) + { + // 页数读取失败 + var hr = (uint)comEx.HResult; + SlidesCount = 0; + LogHelper.WriteLogToFile($"读取PPT页数失败: {comEx.Message} (HR: 0x{hr:X8})", LogHelper.LogType.Warning); + } // 获取当前幻灯片 try diff --git a/Ink Canvas/Helpers/PPTUIManager.cs b/Ink Canvas/Helpers/PPTUIManager.cs index b022a29b..1e29affc 100644 --- a/Ink Canvas/Helpers/PPTUIManager.cs +++ b/Ink Canvas/Helpers/PPTUIManager.cs @@ -81,10 +81,19 @@ namespace Ink_Canvas.Helpers _mainWindow.BtnPPTSlideShow.Visibility = Visibility.Collapsed; _mainWindow.BtnPPTSlideShowEnd.Visibility = Visibility.Visible; + // 只有在页数有效时才更新页码显示 if (currentSlide > 0 && totalSlides > 0) { _mainWindow.PPTBtnPageNow.Text = currentSlide.ToString(); _mainWindow.PPTBtnPageTotal.Text = $"/ {totalSlides}"; + LogHelper.WriteLogToFile($"更新PPT页码显示: {currentSlide}/{totalSlides}", LogHelper.LogType.Trace); + } + else + { + // 页数无效时清空页码显示 + _mainWindow.PPTBtnPageNow.Text = "?"; + _mainWindow.PPTBtnPageTotal.Text = "/ ?"; + LogHelper.WriteLogToFile($"PPT页数无效,清空页码显示: 当前页={currentSlide}, 总页数={totalSlides}", LogHelper.LogType.Warning); } UpdateNavigationPanelsVisibility(); @@ -113,8 +122,20 @@ namespace Ink_Canvas.Helpers { try { - _mainWindow.PPTBtnPageNow.Text = currentSlide.ToString(); - _mainWindow.PPTBtnPageTotal.Text = $"/ {totalSlides}"; + // 只有在页数有效时才更新页码显示 + if (currentSlide > 0 && totalSlides > 0) + { + _mainWindow.PPTBtnPageNow.Text = currentSlide.ToString(); + _mainWindow.PPTBtnPageTotal.Text = $"/ {totalSlides}"; + LogHelper.WriteLogToFile($"更新PPT页码显示: {currentSlide}/{totalSlides}", LogHelper.LogType.Trace); + } + else + { + // 页数无效时清空页码显示 + _mainWindow.PPTBtnPageNow.Text = "?"; + _mainWindow.PPTBtnPageTotal.Text = "/ ?"; + LogHelper.WriteLogToFile($"PPT页数无效,清空页码显示: 当前页={currentSlide}, 总页数={totalSlides}", LogHelper.LogType.Warning); + } } catch (Exception ex) { @@ -156,17 +177,25 @@ namespace Ink_Canvas.Helpers try { // 检查是否应该显示PPT按钮 - // 不仅要检查按钮设置,还要确保确实在PPT放映模式下 + // 不仅要检查按钮设置,还要确保确实在PPT放映模式下且页数有效 + bool isInSlideShow = _mainWindow.PPTManager?.IsInSlideShow == true; + int slidesCount = _mainWindow.PPTManager?.SlidesCount ?? 0; + bool hasValidPageCount = slidesCount > 0; + bool shouldShowButtons = ShowPPTButton && _mainWindow.BtnPPTSlideShowEnd.Visibility == Visibility.Visible && - _mainWindow.PPTManager?.IsInSlideShow == true; + isInSlideShow && + hasValidPageCount; if (!shouldShowButtons) { HideAllNavigationPanels(); + LogHelper.WriteLogToFile($"隐藏PPT导航面板 - 放映状态: {isInSlideShow}, 页数: {slidesCount}, 按钮设置: {ShowPPTButton}", LogHelper.LogType.Trace); return; } + LogHelper.WriteLogToFile($"显示PPT导航面板 - 放映状态: {isInSlideShow}, 页数: {slidesCount}", LogHelper.LogType.Trace); + // 设置侧边按钮位置 _mainWindow.LeftSidePanelForPPTNavigation.Margin = new Thickness(0, 0, 0, PPTLSButtonPosition * 2); _mainWindow.RightSidePanelForPPTNavigation.Margin = new Thickness(0, 0, 0, PPTRSButtonPosition * 2); diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs index 3b976f54..80b400cb 100644 --- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs +++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs @@ -2,6 +2,7 @@ using Ink_Canvas.Helpers; using iNKORE.UI.WPF.Modern; using System; using System.Diagnostics; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -13,6 +14,7 @@ using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Imaging; +using System.Windows.Threading; using Application = System.Windows.Application; using Button = System.Windows.Controls.Button; using Cursors = System.Windows.Input.Cursors; @@ -946,10 +948,45 @@ namespace Ink_Canvas var randWindow = new RandWindow(Settings); randWindow.Show(); - // 确保窗口显示后立即置顶 - randWindow.Activate(); - randWindow.Topmost = true; - randWindow.Focus(); + + // 使用延迟确保窗口完全显示后再强制置顶 + randWindow.Dispatcher.BeginInvoke(new Action(() => + { + try + { + // 强制激活窗口 + randWindow.Activate(); + randWindow.Focus(); + + // 设置置顶 + randWindow.Topmost = true; + + // 使用Win32 API强制置顶 + var hwnd = new WindowInteropHelper(randWindow).Handle; + if (hwnd != IntPtr.Zero) + { + const int WS_EX_TOPMOST = 0x00000008; + const int GWL_EXSTYLE = -20; + const int SWP_NOMOVE = 0x0002; + const int SWP_NOSIZE = 0x0001; + const int SWP_SHOWWINDOW = 0x0040; + const int SWP_NOOWNERZORDER = 0x0200; + var HWND_TOPMOST = new IntPtr(-1); + + // 设置窗口样式为置顶 + int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE); + SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST); + + // 强制置顶 + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER); + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"强制置顶RandWindow失败: {ex.Message}", LogHelper.LogType.Error); + } + }), DispatcherPriority.Loaded); } public void CheckEraserTypeTab() @@ -1346,7 +1383,9 @@ namespace Ink_Canvas var toolbarHeight = ForegroundWindowInfo.GetTaskbarHeight(screen, dpiScaleY); // 计算浮动栏位置,考虑快捷调色盘的显示状态 - double floatingBarWidth = ViewboxFloatingBar.ActualWidth * ViewboxFloatingBarScaleTransform.ScaleX; + // 确保获取到正确的浮动栏宽度,如果ActualWidth为0则使用DesiredSize + double baseWidth = ViewboxFloatingBar.ActualWidth > 0 ? ViewboxFloatingBar.ActualWidth : ViewboxFloatingBar.DesiredSize.Width; + double floatingBarWidth = baseWidth * ViewboxFloatingBarScaleTransform.ScaleX; // 如果快捷调色盘显示,确保有足够空间 if ((QuickColorPalettePanel != null && QuickColorPalettePanel.Visibility == Visibility.Visible) || @@ -1467,7 +1506,9 @@ namespace Ink_Canvas var toolbarHeight = ForegroundWindowInfo.GetTaskbarHeight(screen, dpiScaleY); // 计算浮动栏位置,考虑快捷调色盘的显示状态 - double floatingBarWidth = ViewboxFloatingBar.ActualWidth * ViewboxFloatingBarScaleTransform.ScaleX; + // 确保获取到正确的浮动栏宽度,如果ActualWidth为0则使用DesiredSize + double baseWidth = ViewboxFloatingBar.ActualWidth > 0 ? ViewboxFloatingBar.ActualWidth : ViewboxFloatingBar.DesiredSize.Width; + double floatingBarWidth = baseWidth * ViewboxFloatingBarScaleTransform.ScaleX; // 如果快捷调色盘显示,确保有足够空间 if ((QuickColorPalettePanel != null && QuickColorPalettePanel.Visibility == Visibility.Visible) || @@ -1549,7 +1590,9 @@ namespace Ink_Canvas var toolbarHeight = ForegroundWindowInfo.GetTaskbarHeight(screen, dpiScaleY); // 计算浮动栏位置,考虑快捷调色盘的显示状态 - double floatingBarWidth = ViewboxFloatingBar.ActualWidth * ViewboxFloatingBarScaleTransform.ScaleX; + // 确保获取到正确的浮动栏宽度,如果ActualWidth为0则使用DesiredSize + double baseWidth = ViewboxFloatingBar.ActualWidth > 0 ? ViewboxFloatingBar.ActualWidth : ViewboxFloatingBar.DesiredSize.Width; + double floatingBarWidth = baseWidth * ViewboxFloatingBarScaleTransform.ScaleX; // 如果快捷调色盘显示,确保有足够空间 if ((QuickColorPalettePanel != null && QuickColorPalettePanel.Visibility == Visibility.Visible) || diff --git a/Ink Canvas/MainWindow_cs/MW_Settings.cs b/Ink Canvas/MainWindow_cs/MW_Settings.cs index 1afb5732..eafd870b 100644 --- a/Ink Canvas/MainWindow_cs/MW_Settings.cs +++ b/Ink Canvas/MainWindow_cs/MW_Settings.cs @@ -197,14 +197,22 @@ namespace Ink_Canvas val > 0.5 && val < 1.25 ? val : val <= 0.5 ? 0.5 : val >= 1.25 ? 1.25 : 1; ViewboxFloatingBarScaleTransform.ScaleY = val > 0.5 && val < 1.25 ? val : val <= 0.5 ? 0.5 : val >= 1.25 ? 1.25 : 1; - // auto align - 新增:只在屏幕模式下重新计算浮动栏位置 - if (currentMode == 0) + + // 等待UI更新后再重新计算浮动栏位置,确保居中计算准确 + Dispatcher.BeginInvoke(new Action(() => { - if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible) - ViewboxFloatingBarMarginAnimation(60); - else - ViewboxFloatingBarMarginAnimation(100, true); - } + // 强制更新布局以确保ActualWidth正确 + ViewboxFloatingBar.UpdateLayout(); + + // auto align - 新增:只在屏幕模式下重新计算浮动栏位置 + if (currentMode == 0) + { + if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible) + ViewboxFloatingBarMarginAnimation(60); + else + ViewboxFloatingBarMarginAnimation(100, true); + } + }), DispatcherPriority.Render); } private void ViewboxFloatingBarOpacityValueSlider_ValueChanged(object sender, RoutedEventArgs e) diff --git a/Ink Canvas/Windows/CountdownTimerWindow.xaml b/Ink Canvas/Windows/CountdownTimerWindow.xaml index 8c785503..37372edb 100644 --- a/Ink Canvas/Windows/CountdownTimerWindow.xaml +++ b/Ink Canvas/Windows/CountdownTimerWindow.xaml @@ -24,23 +24,11 @@ Margin="0,0,0,0" Visibility="Collapsed" Foreground="#5B5D5F" Text="00" FontSize="26"/> - - - - - - - - - - - - - - +