diff --git a/Ink Canvas.sln b/Ink Canvas.sln index 0daac4d2..29bb5abd 100644 --- a/Ink Canvas.sln +++ b/Ink Canvas.sln @@ -1,9 +1,16 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.33530.505 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InkCanvasForClass", "Ink Canvas\InkCanvasForClass.csproj", "{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InkCanvas.PluginSdk", "Plugins\SDK\InkCanvas.PluginSdk.csproj", "{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InkCanvas.PluginHost", "Plugins\Host\InkCanvas.PluginHost.csproj", "{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleClockPlugin", "Plugins\Samples\SampleClockPlugin\SampleClockPlugin.csproj", "{60891C83-8F04-438E-8064-D827E7AC1817}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -38,6 +45,66 @@ Global {8D0EDFC7-F974-4571-BC49-6F3A6653FE81}.Release|x64.Build.0 = Release|Any CPU {8D0EDFC7-F974-4571-BC49-6F3A6653FE81}.Release|x86.ActiveCfg = Release|Any CPU {8D0EDFC7-F974-4571-BC49-6F3A6653FE81}.Release|x86.Build.0 = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|ARM.ActiveCfg = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|ARM.Build.0 = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|ARM64.Build.0 = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|x64.ActiveCfg = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|x64.Build.0 = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|x86.ActiveCfg = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|x86.Build.0 = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|Any CPU.Build.0 = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|ARM.ActiveCfg = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|ARM.Build.0 = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|ARM64.ActiveCfg = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|ARM64.Build.0 = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|x64.ActiveCfg = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|x64.Build.0 = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|x86.ActiveCfg = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|x86.Build.0 = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|ARM.ActiveCfg = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|ARM.Build.0 = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|ARM64.Build.0 = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|x64.ActiveCfg = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|x64.Build.0 = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|x86.ActiveCfg = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|x86.Build.0 = Debug|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|Any CPU.Build.0 = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|ARM.ActiveCfg = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|ARM.Build.0 = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|ARM64.ActiveCfg = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|ARM64.Build.0 = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|x64.ActiveCfg = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|x64.Build.0 = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|x86.ActiveCfg = Release|Any CPU + {E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|x86.Build.0 = Release|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Debug|ARM.ActiveCfg = Debug|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Debug|ARM.Build.0 = Debug|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Debug|ARM64.Build.0 = Debug|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Debug|x64.ActiveCfg = Debug|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Debug|x64.Build.0 = Debug|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Debug|x86.ActiveCfg = Debug|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Debug|x86.Build.0 = Debug|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Release|Any CPU.Build.0 = Release|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Release|ARM.ActiveCfg = Release|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Release|ARM.Build.0 = Release|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Release|ARM64.ActiveCfg = Release|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Release|ARM64.Build.0 = Release|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Release|x64.ActiveCfg = Release|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Release|x64.Build.0 = Release|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Release|x86.ActiveCfg = Release|Any CPU + {60891C83-8F04-438E-8064-D827E7AC1817}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Ink Canvas/Helpers/Plugins/EnhancedPluginBase.cs b/Ink Canvas/Helpers/Plugins/EnhancedPluginBase.cs deleted file mode 100644 index d22ca80e..00000000 --- a/Ink Canvas/Helpers/Plugins/EnhancedPluginBase.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System.Windows.Controls; - -namespace Ink_Canvas.Helpers.Plugins -{ - /// - /// 增强的插件基类,提供对插件服务的访问和基本实现 - /// - public abstract class EnhancedPluginBase : PluginBase, IEnhancedPlugin - { - /// - /// 插件服务实例 - /// - public IPluginService PluginService { get; private set; } - - /// - /// 构造函数 - /// - protected EnhancedPluginBase() - { - PluginService = 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} 配置已变更"); - } - - /// - /// 重写初始化方法,调用OnStartup - /// - public override void Initialize() - { - base.Initialize(); - OnStartup(); - } - - /// - /// 重写清理方法,调用OnShutdown - /// - public override void Cleanup() - { - OnShutdown(); - base.Cleanup(); - } - } -} \ No newline at end of file diff --git a/Ink Canvas/Helpers/Plugins/EnhancedPluginBaseV2.cs b/Ink Canvas/Helpers/Plugins/EnhancedPluginBaseV2.cs deleted file mode 100644 index 218068b6..00000000 --- a/Ink Canvas/Helpers/Plugins/EnhancedPluginBaseV2.cs +++ /dev/null @@ -1,241 +0,0 @@ -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/ICCPPPluginAdapter.cs b/Ink Canvas/Helpers/Plugins/ICCPPPluginAdapter.cs index e018ac0d..4287225d 100644 --- a/Ink Canvas/Helpers/Plugins/ICCPPPluginAdapter.cs +++ b/Ink Canvas/Helpers/Plugins/ICCPPPluginAdapter.cs @@ -14,6 +14,8 @@ namespace Ink_Canvas.Helpers.Plugins private readonly Version _pluginVersion; private bool _isInitialized; + public override string PluginStateKey => "ICCPP:" + (_pluginPath ?? string.Empty); + /// /// 创建 ICCPP 插件适配器 /// diff --git a/Ink Canvas/Helpers/Plugins/IEnhancedPlugin.cs b/Ink Canvas/Helpers/Plugins/IEnhancedPlugin.cs deleted file mode 100644 index 312eb10c..00000000 --- a/Ink Canvas/Helpers/Plugins/IEnhancedPlugin.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Windows.Controls; - -namespace Ink_Canvas.Helpers.Plugins -{ - /// - /// 增强的插件接口,提供对插件服务的访问 - /// - public interface IEnhancedPlugin : IPlugin - { - /// - /// 获取插件服务实例 - /// - IPluginService PluginService { get; } - - /// - /// 插件启动时调用,在Initialize之后 - /// - void OnStartup(); - - /// - /// 插件关闭时调用,在Cleanup之前 - /// - void OnShutdown(); - - /// - /// 获取插件的菜单项 - /// - /// 菜单项集合 - MenuItem[] GetMenuItems(); - - /// - /// 获取插件的工具栏按钮 - /// - /// 工具栏按钮集合 - Button[] GetToolbarButtons(); - - /// - /// 获取插件的状态栏信息 - /// - /// 状态栏信息 - string GetStatusBarInfo(); - - /// - /// 插件配置变更时调用 - /// - void OnConfigurationChanged(); - } -} \ No newline at end of file diff --git a/Ink Canvas/Helpers/Plugins/IGetService.cs b/Ink Canvas/Helpers/Plugins/IGetService.cs index ab48889a..60f299ba 100644 --- a/Ink Canvas/Helpers/Plugins/IGetService.cs +++ b/Ink Canvas/Helpers/Plugins/IGetService.cs @@ -20,12 +20,12 @@ namespace Ink_Canvas.Helpers.Plugins /// /// 获取当前画布 /// - InkCanvas CurrentCanvas { get; } + global::System.Windows.Controls.InkCanvas CurrentCanvas { get; } /// /// 获取所有画布页面 /// - List AllCanvasPages { get; } + List AllCanvasPages { get; } /// /// 获取当前页面索引 diff --git a/Ink Canvas/Helpers/Plugins/PluginBase.cs b/Ink Canvas/Helpers/Plugins/PluginBase.cs index 716b7e61..0c960100 100644 --- a/Ink Canvas/Helpers/Plugins/PluginBase.cs +++ b/Ink Canvas/Helpers/Plugins/PluginBase.cs @@ -34,6 +34,11 @@ namespace Ink_Canvas.Helpers.Plugins /// public string Id { get; protected set; } + /// + /// 写入 配置时使用的稳定键(默认同类型全名;多实例类型如 SDK 目录插件应重写)。 + /// + public virtual string PluginStateKey => GetType().FullName; + /// /// 插件路径 /// diff --git a/Ink Canvas/Helpers/Plugins/PluginConfigurationManager.cs b/Ink Canvas/Helpers/Plugins/PluginConfigurationManager.cs deleted file mode 100644 index 9688cd31..00000000 --- a/Ink Canvas/Helpers/Plugins/PluginConfigurationManager.cs +++ /dev/null @@ -1,273 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; - -namespace Ink_Canvas.Helpers.Plugins -{ - /// - /// 插件配置管理器,允许插件管理自己的配置 - /// - public class PluginConfigurationManager - { - private static readonly string PluginConfigDirectory = Path.Combine(App.RootPath, "PluginConfigs"); - private static readonly Dictionary> _pluginConfigs = new Dictionary>(); - private static readonly object _lockObject = new object(); - - static PluginConfigurationManager() - { - // 确保配置目录存在 - if (!Directory.Exists(PluginConfigDirectory)) - { - Directory.CreateDirectory(PluginConfigDirectory); - } - } - - /// - /// 获取插件配置值 - /// - /// 配置值类型 - /// 插件名称 - /// 配置键 - /// 默认值 - /// 配置值 - public static T GetConfiguration(string pluginName, string key, T defaultValue = default(T)) - { - lock (_lockObject) - { - try - { - if (_pluginConfigs.TryGetValue(pluginName, out var pluginConfig)) - { - if (pluginConfig.TryGetValue(key, out var value)) - { - if (value is T typedValue) - { - return typedValue; - } - - // 尝试类型转换 - try - { - return (T)Convert.ChangeType(value, typeof(T)); - } - catch - { - return defaultValue; - } - } - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"获取插件 {pluginName} 配置 {key} 时出错: {ex.Message}", LogHelper.LogType.Error); - } - - return defaultValue; - } - } - - /// - /// 设置插件配置值 - /// - /// 配置值类型 - /// 插件名称 - /// 配置键 - /// 配置值 - public static void SetConfiguration(string pluginName, string key, T value) - { - lock (_lockObject) - { - try - { - if (!_pluginConfigs.ContainsKey(pluginName)) - { - _pluginConfigs[pluginName] = new Dictionary(); - } - - _pluginConfigs[pluginName][key] = value; - - // 异步保存配置 - Task.Run(() => SavePluginConfiguration(pluginName)); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"设置插件 {pluginName} 配置 {key} 时出错: {ex.Message}", LogHelper.LogType.Error); - } - } - } - - /// - /// 删除插件配置 - /// - /// 插件名称 - /// 配置键 - public static void RemoveConfiguration(string pluginName, string key) - { - lock (_lockObject) - { - try - { - if (_pluginConfigs.TryGetValue(pluginName, out var pluginConfig)) - { - if (pluginConfig.Remove(key)) - { - // 异步保存配置 - Task.Run(() => SavePluginConfiguration(pluginName)); - } - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"删除插件 {pluginName} 配置 {key} 时出错: {ex.Message}", LogHelper.LogType.Error); - } - } - } - - /// - /// 获取插件的所有配置 - /// - /// 插件名称 - /// 配置字典 - public static Dictionary GetAllConfigurations(string pluginName) - { - lock (_lockObject) - { - if (_pluginConfigs.TryGetValue(pluginName, out var pluginConfig)) - { - return new Dictionary(pluginConfig); - } - return new Dictionary(); - } - } - - /// - /// 清除插件的所有配置 - /// - /// 插件名称 - public static void ClearAllConfigurations(string pluginName) - { - lock (_lockObject) - { - try - { - if (_pluginConfigs.Remove(pluginName)) - { - // 删除配置文件 - string configFile = Path.Combine(PluginConfigDirectory, $"{pluginName}.json"); - if (File.Exists(configFile)) - { - File.Delete(configFile); - } - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"清除插件 {pluginName} 所有配置时出错: {ex.Message}", LogHelper.LogType.Error); - } - } - } - - /// - /// 加载插件配置 - /// - /// 插件名称 - public static void LoadPluginConfiguration(string pluginName) - { - try - { - string configFile = Path.Combine(PluginConfigDirectory, $"{pluginName}.json"); - if (File.Exists(configFile)) - { - string json = File.ReadAllText(configFile); - var config = JsonConvert.DeserializeObject>(json); - - lock (_lockObject) - { - _pluginConfigs[pluginName] = config ?? new Dictionary(); - } - - LogHelper.WriteLogToFile($"已加载插件 {pluginName} 的配置"); - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"加载插件 {pluginName} 配置时出错: {ex.Message}", LogHelper.LogType.Error); - } - } - - /// - /// 保存插件配置 - /// - /// 插件名称 - private static void SavePluginConfiguration(string pluginName) - { - try - { - Dictionary pluginConfig; - lock (_lockObject) - { - if (!_pluginConfigs.TryGetValue(pluginName, out pluginConfig)) - { - return; - } - } - - string configFile = Path.Combine(PluginConfigDirectory, $"{pluginName}.json"); - string json = JsonConvert.SerializeObject(pluginConfig, Formatting.Indented); - File.WriteAllText(configFile, json); - - LogHelper.WriteLogToFile($"已保存插件 {pluginName} 的配置"); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"保存插件 {pluginName} 配置时出错: {ex.Message}", LogHelper.LogType.Error); - } - } - - /// - /// 加载所有插件的配置 - /// - public static void LoadAllPluginConfigurations() - { - try - { - if (Directory.Exists(PluginConfigDirectory)) - { - string[] configFiles = Directory.GetFiles(PluginConfigDirectory, "*.json"); - foreach (string configFile in configFiles) - { - string pluginName = Path.GetFileNameWithoutExtension(configFile); - LoadPluginConfiguration(pluginName); - } - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"加载所有插件配置时出错: {ex.Message}", LogHelper.LogType.Error); - } - } - - /// - /// 保存所有插件的配置 - /// - public static void SaveAllPluginConfigurations() - { - try - { - lock (_lockObject) - { - foreach (string pluginName in _pluginConfigs.Keys) - { - SavePluginConfiguration(pluginName); - } - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"保存所有插件配置时出错: {ex.Message}", LogHelper.LogType.Error); - } - } - } -} \ No newline at end of file diff --git a/Ink Canvas/Helpers/Plugins/PluginManager.cs b/Ink Canvas/Helpers/Plugins/PluginManager.cs index 9e018183..82c4c7d0 100644 --- a/Ink Canvas/Helpers/Plugins/PluginManager.cs +++ b/Ink Canvas/Helpers/Plugins/PluginManager.cs @@ -1,4 +1,6 @@ using Ink_Canvas.Windows; +using InkCanvasForClass.PluginHost; +using InkCanvasForClass.PluginSdk; using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -71,6 +73,23 @@ namespace Ink_Canvas.Helpers.Plugins /// private Dictionary _pluginHashes = new Dictionary(); + /// + /// SDK 插件程序集(按主 DLL 路径缓存) + /// + private readonly Dictionary _sdkAssembliesByPath = + new Dictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// 已加载的 SDK 插件核心实例(键为插件目录名) + /// + private readonly Dictionary _sdkCoreByFolderId = + new Dictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// SDK 插件登记的菜单 / 工具栏 / 设置页,供主窗口挂载。 + /// + public CollectingPluginRegistry ExtensionRegistry { get; } = new CollectingPluginRegistry(); + private PluginManager() { // 确保插件目录存在 @@ -102,6 +121,60 @@ namespace Ink_Canvas.Helpers.Plugins }; } + private static string GetPluginStateKey(IPlugin plugin) + { + if (plugin is PluginBase pluginBase) + { + return pluginBase.PluginStateKey; + } + + return plugin.GetType().FullName; + } + + public IInkCanvasPlugin GetSdkPluginInstance(string folderId) + { + if (string.IsNullOrEmpty(folderId)) + { + return null; + } + + return _sdkCoreByFolderId.TryGetValue(folderId, out var core) ? core : null; + } + + public IReadOnlyList GetAllSdkPluginInstances() + { + return _sdkCoreByFolderId.Values.ToList(); + } + + public IInkCanvasPlugin GetSdkPluginByName(string name) + { + return _sdkCoreByFolderId.Values.FirstOrDefault(p => p.Name == name); + } + + public void SetSdkPluginEnabledByName(string name, bool enable) + { + var adapter = Plugins.OfType().FirstOrDefault(a => + a.Name == name || string.Equals(a.FolderId, name, StringComparison.OrdinalIgnoreCase)); + if (adapter == null) + { + return; + } + + TogglePlugin(adapter, enable); + } + + public void UnloadSdkPluginByName(string name) + { + var adapter = Plugins.OfType().FirstOrDefault(a => + a.Name == name || string.Equals(a.FolderId, name, StringComparison.OrdinalIgnoreCase)); + if (adapter == null) + { + return; + } + + UnloadPlugin(adapter, true); + } + /// /// 初始化插件系统 /// @@ -123,6 +196,10 @@ namespace Ink_Canvas.Helpers.Plugins LogHelper.WriteLogToFile("正在加载外部插件..."); LoadExternalPlugins(); + // 加载 Plugins 子目录中的 SDK 插件(IInkCanvasPlugin) + LogHelper.WriteLogToFile("正在加载 SDK 插件(子目录)..."); + LoadSdkPluginsFromSubfolders(); + // 启用已配置为启用的插件 LogHelper.WriteLogToFile("正在应用配置的插件状态..."); EnableConfiguredPlugins(); @@ -214,6 +291,87 @@ namespace Ink_Canvas.Helpers.Plugins } } + /// + /// 扫描 下一层子目录,加载实现 的 SDK 插件。 + /// + private void LoadSdkPluginsFromSubfolders() + { + try + { + if (!Directory.Exists(PluginsDirectory)) + { + return; + } + + foreach (var pluginDir in Directory.GetDirectories(PluginsDirectory)) + { + var folderId = Path.GetFileName(pluginDir.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)); + if (string.IsNullOrEmpty(folderId)) + { + continue; + } + + var dllFiles = Directory.GetFiles(pluginDir, "*.dll", SearchOption.AllDirectories); + var mainDll = dllFiles.FirstOrDefault(f => + f.IndexOf($"{Path.DirectorySeparatorChar}lib{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase) < 0 && + f.IndexOf($"{Path.AltDirectorySeparatorChar}lib{Path.AltDirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase) < 0 && + f.IndexOf($"{Path.DirectorySeparatorChar}runtimes{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase) < 0 && + f.IndexOf($"{Path.AltDirectorySeparatorChar}runtimes{Path.AltDirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase) < 0); + + if (mainDll == null) + { + continue; + } + + try + { + if (!_sdkAssembliesByPath.TryGetValue(mainDll, out var assembly)) + { + assembly = Assembly.LoadFrom(mainDll); + _sdkAssembliesByPath[mainDll] = assembly; + } + + Type pluginType = null; + try + { + pluginType = assembly.GetTypes() + .FirstOrDefault(t => + typeof(IInkCanvasPlugin).IsAssignableFrom(t) && + !t.IsAbstract && + !t.IsInterface && + t.IsClass); + } + catch (ReflectionTypeLoadException ex) + { + LogHelper.WriteLogToFile($"枚举 SDK 插件类型失败 {folderId}: {ex.Message}", LogHelper.LogType.Error); + } + + if (pluginType == null) + { + continue; + } + + var core = (IInkCanvasPlugin)Activator.CreateInstance(pluginType); + _sdkCoreByFolderId[folderId] = core; + + var adapter = new SdkPluginAdapter(folderId, core, mainDll); + adapter.Initialize(); + Plugins.Add(adapter); + + LogHelper.WriteLogToFile($"已加载 SDK 插件(子目录): {core.Name} — {folderId}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"加载 SDK 插件目录 {folderId} 失败: {ex.Message}", LogHelper.LogType.Error); + } + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"扫描 SDK 插件子目录失败: {ex.Message}", LogHelper.LogType.Error); + } + } + /// /// 加载单个外部插件 /// @@ -349,7 +507,7 @@ namespace Ink_Canvas.Helpers.Plugins { try { - string pluginTypeName = plugin.GetType().FullName; + string pluginTypeName = GetPluginStateKey(plugin); // 检查配置中的插件状态 if (PluginStates.TryGetValue(pluginTypeName, out bool enabled)) @@ -434,7 +592,7 @@ namespace Ink_Canvas.Helpers.Plugins { if (sender is IPlugin plugin) { - string pluginTypeName = plugin.GetType().FullName; + string pluginTypeName = GetPluginStateKey(plugin); // 更新配置状态 if (!PluginStates.ContainsKey(pluginTypeName) || PluginStates[pluginTypeName] != isEnabled) @@ -537,7 +695,7 @@ namespace Ink_Canvas.Helpers.Plugins // 保存插件的当前状态 bool wasEnabled = plugin.IsEnabled; - string pluginTypeName = plugin.GetType().FullName; + string pluginTypeName = GetPluginStateKey(plugin); // 卸载插件 UnloadPlugin(plugin); @@ -564,7 +722,7 @@ namespace Ink_Canvas.Helpers.Plugins } // 更新配置(如果类型名称变化) - string newPluginTypeName = newPlugin.GetType().FullName; + string newPluginTypeName = GetPluginStateKey(newPlugin); if (pluginTypeName != newPluginTypeName && PluginStates.ContainsKey(pluginTypeName)) { bool state = PluginStates[pluginTypeName]; @@ -614,10 +772,15 @@ namespace Ink_Canvas.Helpers.Plugins // 从插件集合中移除 Plugins.Remove(plugin); + if (plugin is SdkPluginAdapter sdkAdapter) + { + _sdkCoreByFolderId.Remove(sdkAdapter.FolderId); + } + // 从配置中移除(如果需要) if (removeFromConfig && plugin.GetType() != null) { - string pluginTypeName = plugin.GetType().FullName; + string pluginTypeName = GetPluginStateKey(plugin); if (PluginStates.ContainsKey(pluginTypeName)) { PluginStates.Remove(pluginTypeName); @@ -706,7 +869,7 @@ namespace Ink_Canvas.Helpers.Plugins // 记录插件信息,用于日志 string pluginName = plugin.Name; - string pluginTypeName = plugin.GetType().FullName; + string pluginTypeName = GetPluginStateKey(plugin); LogHelper.WriteLogToFile($"开始切换插件 {pluginName} 状态为: {(enable ? "启用" : "禁用")}"); @@ -919,7 +1082,7 @@ namespace Ink_Canvas.Helpers.Plugins if (!string.IsNullOrEmpty(pluginPath) && File.Exists(pluginPath)) { // 记录插件类型名称,用于后续状态检查 - string pluginTypeName = plugin.GetType().FullName; + string pluginTypeName = GetPluginStateKey(plugin); bool targetState = enable; // 使用调度器确保在UI线程执行热重载 @@ -1322,7 +1485,7 @@ namespace Ink_Canvas.Helpers.Plugins // 对比配置,查找变更的插件 foreach (var plugin in Plugins.ToList()) // 创建副本进行遍历,避免集合修改异常 { - string pluginTypeName = plugin.GetType().FullName; + string pluginTypeName = GetPluginStateKey(plugin); // 检查插件在配置中是否存在 if (PluginStates.TryGetValue(pluginTypeName, out bool shouldBeEnabled)) diff --git a/Ink Canvas/Helpers/Plugins/PluginRuntime.cs b/Ink Canvas/Helpers/Plugins/PluginRuntime.cs new file mode 100644 index 00000000..a3ea7ec2 --- /dev/null +++ b/Ink Canvas/Helpers/Plugins/PluginRuntime.cs @@ -0,0 +1,25 @@ +namespace Ink_Canvas.Helpers.Plugins +{ + /// + /// 在加载任何 SDK 插件之前初始化宿主上下文(实现 )。 + /// + public static class PluginRuntime + { + private static PluginSdkHostContext _context; + + public static PluginSdkHostContext SdkContext => _context; + + /// 相同实例,便于旧代码通过 访问。 + public static IPluginService Services => SdkContext != null ? (IPluginService)SdkContext : null; + + public static void Initialize(MainWindow mainWindow) + { + if (_context == null) + { + _context = new PluginSdkHostContext(); + } + + _context.SetMainWindow(mainWindow); + } + } +} diff --git a/Ink Canvas/Helpers/Plugins/PluginSdkHostContext.cs b/Ink Canvas/Helpers/Plugins/PluginSdkHostContext.cs new file mode 100644 index 00000000..e5b9db97 --- /dev/null +++ b/Ink Canvas/Helpers/Plugins/PluginSdkHostContext.cs @@ -0,0 +1,1289 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Ink; +using Ink_Canvas.Windows; +using InkCanvasForClass.PluginSdk; +using LegacyNotificationType = Ink_Canvas.Helpers.Plugins.NotificationType; + +namespace Ink_Canvas.Helpers.Plugins +{ + /// + /// 统一宿主上下文:同时实现 SDK 的 与旧版 。 + /// + public class PluginSdkHostContext : IPluginContext, IPluginService + { + private MainWindow _mainWindow; + private Dictionary _eventHandlers = new Dictionary(); + + /// + /// 设置主窗口引用 + /// + /// 主窗口实例 + public void SetMainWindow(MainWindow mainWindow) + { + _mainWindow = mainWindow; + } + + #region 窗口和UI访问 + + public Window MainWindow => _mainWindow; + + public System.Windows.Controls.InkCanvas CurrentCanvas => _mainWindow?.inkCanvas; + + public IList AllCanvasPages => + _mainWindow?.WhiteboardPages ?? new List(); + + public int CurrentPageIndex => _mainWindow?.CurrentPageIndex ?? 0; + + public int TotalPageCount => _mainWindow?.WhiteboardPages?.Count ?? 0; + + public FrameworkElement FloatingToolBar => _mainWindow?.ViewboxFloatingBar; + + public FrameworkElement LeftPanel => _mainWindow?.BlackboardLeftSide; + + public FrameworkElement RightPanel => _mainWindow?.BlackboardRightSide; + + public FrameworkElement TopPanel => _mainWindow?.BorderTools; + + public FrameworkElement BottomPanel => _mainWindow?.BorderSettings; + + #endregion + + #region 绘制工具状态 + + public int CurrentDrawingMode => GetCurrentDrawingMode(); + + public double CurrentInkWidth => GetCurrentInkWidth(); + + public Color CurrentInkColor => GetCurrentInkColor(); + + public double CurrentHighlighterWidth => GetCurrentHighlighterWidth(); + + public int CurrentEraserSize => GetCurrentEraserSize(); + + public int CurrentEraserType => GetCurrentEraserType(); + + public int CurrentEraserShape => GetCurrentEraserShape(); + + public double CurrentInkAlpha => GetCurrentInkAlpha(); + + public int CurrentInkStyle => GetCurrentInkStyle(); + + public string CurrentBackgroundColor => GetCurrentBackgroundColor(); + + #endregion + + #region 应用状态 + + public bool IsDarkTheme => GetIsDarkTheme(); + + public bool IsWhiteboardMode => GetIsWhiteboardMode(); + + public bool IsPPTMode => GetIsPPTMode(); + + public bool IsFullScreenMode => GetIsFullScreenMode(); + + public bool IsCanvasMode => GetIsCanvasMode(); + + public bool IsSelectionMode => GetIsSelectionMode(); + + public bool IsEraserMode => GetIsEraserMode(); + + public bool IsShapeDrawingMode => GetIsShapeDrawingMode(); + + public bool IsHighlighterMode => GetIsHighlighterMode(); + + #endregion + + #region 操作状态 + + public bool CanUndo => GetCanUndo(); + + public bool CanRedo => GetCanRedo(); + + #endregion + + #region 设置管理 + + public T GetSetting(string key, T defaultValue = default(T)) + { + try + { + // 这里需要根据实际的设置系统来实现 + // 暂时返回默认值 + return defaultValue; + } + catch + { + return defaultValue; + } + } + + public void SetSetting(string key, T value) + { + try + { + // 这里需要根据实际的设置系统来实现 + LogHelper.WriteLogToFile($"设置 {key} = {value}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置 {key} 时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SaveSettings() + { + try + { + // 这里需要根据实际的设置系统来实现 + LogHelper.WriteLogToFile("设置已保存"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"保存设置时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void LoadSettings() + { + try + { + // 这里需要根据实际的设置系统来实现 + LogHelper.WriteLogToFile("设置已加载"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"加载设置时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void ResetSettings() + { + try + { + // 这里需要根据实际的设置系统来实现 + LogHelper.WriteLogToFile("设置已重置"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"重置设置时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + #endregion + + #region 插件管理 + + public IList GetAllPlugins() + { + return PluginManager.Instance.GetAllSdkPluginInstances().ToList(); + } + + public IInkCanvasPlugin GetPlugin(string pluginName) + { + return PluginManager.Instance.GetSdkPluginByName(pluginName); + } + + public void EnablePlugin(string pluginName) + { + if (PluginManager.Instance.GetSdkPluginByName(pluginName) != null) + { + PluginManager.Instance.SetSdkPluginEnabledByName(pluginName, true); + return; + } + + var plugin = PluginManager.Instance.Plugins.FirstOrDefault(p => p.Name == pluginName); + if (plugin != null) + { + PluginManager.Instance.TogglePlugin(plugin, true); + } + } + + public void DisablePlugin(string pluginName) + { + if (PluginManager.Instance.GetSdkPluginByName(pluginName) != null) + { + PluginManager.Instance.SetSdkPluginEnabledByName(pluginName, false); + return; + } + + var plugin = PluginManager.Instance.Plugins.FirstOrDefault(p => p.Name == pluginName); + if (plugin != null) + { + PluginManager.Instance.TogglePlugin(plugin, false); + } + } + + public void UnloadPlugin(string pluginName) + { + if (PluginManager.Instance.GetSdkPluginByName(pluginName) != null) + { + PluginManager.Instance.UnloadSdkPluginByName(pluginName); + return; + } + + var plugin = PluginManager.Instance.Plugins.FirstOrDefault(p => p.Name == pluginName); + if (plugin != null) + { + PluginManager.Instance.UnloadPlugin(plugin, true); + } + } + + #endregion + + #region 窗口操作 + + public void ShowSettingsWindow() + { + try + { + if (_mainWindow == null) + { + return; + } + + _mainWindow.Dispatcher.BeginInvoke(new Action(() => _mainWindow.BtnSettings_Click(null, null))); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"显示设置窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void HideSettingsWindow() + { + try + { + if (_mainWindow == null) + { + return; + } + + _mainWindow.Dispatcher.BeginInvoke(new Action(() => _mainWindow.HideSubPanels())); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"隐藏设置窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void ShowPluginSettingsWindow() + { + try + { + if (_mainWindow == null) + { + return; + } + + _mainWindow.Dispatcher.BeginInvoke(new Action(() => + { + var w = new PluginSettingsWindow { Owner = _mainWindow }; + w.Show(); + })); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"显示插件设置窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void HidePluginSettingsWindow() + { + try + { + var app = Application.Current; + if (app?.Dispatcher == null) + { + return; + } + + app.Dispatcher.BeginInvoke(new Action(() => + { + foreach (Window w in app.Windows) + { + if (w is PluginSettingsWindow psw) + { + psw.Close(); + } + } + })); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"隐藏插件设置窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void ShowHelpWindow() + { + try + { + // 这里需要调用帮助窗口显示方法 + LogHelper.WriteLogToFile("显示帮助窗口"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"显示帮助窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void HideHelpWindow() + { + try + { + // 这里需要调用帮助窗口隐藏方法 + LogHelper.WriteLogToFile("隐藏帮助窗口"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"隐藏帮助窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void ShowAboutWindow() + { + try + { + // 这里需要调用关于窗口显示方法 + LogHelper.WriteLogToFile("显示关于窗口"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"显示关于窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void HideAboutWindow() + { + try + { + // 这里需要调用关于窗口隐藏方法 + LogHelper.WriteLogToFile("隐藏关于窗口"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"隐藏关于窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void ShowNotification(string message, InkCanvasForClass.PluginSdk.NotificationType type = InkCanvasForClass.PluginSdk.NotificationType.Info) + { + try + { + LogHelper.WriteLogToFile($"通知: {message} ({type})"); + var title = type.ToString(); + _mainWindow?.PluginHost_ShowInfo(title, message); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"显示通知时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public bool ShowConfirmDialog(string message, string title = "确认") + { + try + { + return _mainWindow != null && _mainWindow.PluginHost_ShowConfirm(title, message); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"显示确认对话框时出错: {ex.Message}", LogHelper.LogType.Error); + return false; + } + } + + public string ShowInputDialog(string message, string title = "输入", string defaultValue = "") + { + try + { + return _mainWindow != null + ? _mainWindow.PluginHost_ShowInput(title, message, defaultValue) + : defaultValue; + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"显示输入对话框时出错: {ex.Message}", LogHelper.LogType.Error); + return defaultValue; + } + } + + public void SetFullScreen(bool isFullScreen) + { + try + { + if (_mainWindow == null) + { + return; + } + + _mainWindow.Dispatcher.Invoke(() => + { + _mainWindow.WindowState = isFullScreen ? WindowState.Maximized : WindowState.Normal; + }); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置全屏时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetTopMost(bool isTopMost) + { + try + { + if (_mainWindow == null) + { + return; + } + + _mainWindow.Dispatcher.Invoke(() => _mainWindow.Topmost = isTopMost); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置置顶时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetWindowVisibility(bool isVisible) + { + try + { + if (_mainWindow == null) + { + return; + } + + _mainWindow.Dispatcher.Invoke(() => + _mainWindow.Visibility = isVisible ? Visibility.Visible : Visibility.Hidden); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置窗口可见性时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void MinimizeWindow() + { + try + { + if (_mainWindow != null) + { + _mainWindow.WindowState = WindowState.Minimized; + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"最小化窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void MaximizeWindow() + { + try + { + if (_mainWindow != null) + { + _mainWindow.WindowState = WindowState.Maximized; + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"最大化窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void RestoreWindow() + { + try + { + if (_mainWindow != null) + { + _mainWindow.WindowState = WindowState.Normal; + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"还原窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void CloseWindow() + { + try + { + _mainWindow?.Close(); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"关闭窗口时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetWindowPosition(double x, double y) + { + try + { + if (_mainWindow != null) + { + _mainWindow.Left = x; + _mainWindow.Top = y; + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置窗口位置时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetWindowSize(double width, double height) + { + try + { + if (_mainWindow != null) + { + _mainWindow.Width = width; + _mainWindow.Height = height; + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置窗口大小时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public (double x, double y) GetWindowPosition() + { + try + { + if (_mainWindow != null) + { + return (_mainWindow.Left, _mainWindow.Top); + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"获取窗口位置时出错: {ex.Message}", LogHelper.LogType.Error); + } + return (0, 0); + } + + public (double width, double height) GetWindowSize() + { + try + { + if (_mainWindow != null) + { + return (_mainWindow.Width, _mainWindow.Height); + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"获取窗口大小时出错: {ex.Message}", LogHelper.LogType.Error); + } + return (800, 600); + } + + #endregion + + #region 画布操作 + + public void ClearCanvas() + { + try + { + _mainWindow?.PluginHost_ClearInk(false); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"清除画布时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void ClearAllCanvases() + { + try + { + // 这里需要调用清除所有画布的方法 + LogHelper.WriteLogToFile("清除所有画布"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"清除所有画布时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void AddNewPage() + { + try + { + // 这里需要调用添加新页面的方法 + LogHelper.WriteLogToFile("添加新页面"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"添加新页面时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void DeleteCurrentPage() + { + try + { + // 这里需要调用删除当前页面的方法 + LogHelper.WriteLogToFile("删除当前页面"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"删除当前页面时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SwitchToPage(int pageIndex) + { + try + { + // 这里需要调用切换页面的方法 + LogHelper.WriteLogToFile($"切换到页面: {pageIndex}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"切换页面时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void NextPage() + { + try + { + // 这里需要调用下一页的方法 + LogHelper.WriteLogToFile("下一页"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"下一页时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void PreviousPage() + { + try + { + // 这里需要调用上一页的方法 + LogHelper.WriteLogToFile("上一页"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"上一页时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + #endregion + + #region 绘制设置 + + public void SetDrawingMode(int mode) + { + try + { + // 这里需要调用设置绘制模式的方法 + LogHelper.WriteLogToFile($"设置绘制模式: {mode}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置绘制模式时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetInkWidth(double width) + { + try + { + // 这里需要调用设置墨迹宽度的方法 + LogHelper.WriteLogToFile($"设置墨迹宽度: {width}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置墨迹宽度时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetInkColor(Color color) + { + try + { + // 这里需要调用设置墨迹颜色的方法 + LogHelper.WriteLogToFile($"设置墨迹颜色: {color}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置墨迹颜色时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetHighlighterWidth(double width) + { + try + { + // 这里需要调用设置高亮笔宽度的方法 + LogHelper.WriteLogToFile($"设置高亮笔宽度: {width}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置高亮笔宽度时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetEraserSize(int size) + { + try + { + // 这里需要调用设置橡皮擦大小的方法 + LogHelper.WriteLogToFile($"设置橡皮擦大小: {size}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置橡皮擦大小时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetEraserType(int type) + { + try + { + // 这里需要调用设置橡皮擦类型的方法 + LogHelper.WriteLogToFile($"设置橡皮擦类型: {type}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置橡皮擦类型时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetEraserShape(int shape) + { + try + { + // 这里需要调用设置橡皮擦形状的方法 + LogHelper.WriteLogToFile($"设置橡皮擦形状: {shape}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置橡皮擦形状时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetInkAlpha(double alpha) + { + try + { + // 这里需要调用设置墨迹透明度的方法 + LogHelper.WriteLogToFile($"设置墨迹透明度: {alpha}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置墨迹透明度时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetInkStyle(int style) + { + try + { + // 这里需要调用设置墨迹样式的方法 + LogHelper.WriteLogToFile($"设置墨迹样式: {style}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置墨迹样式时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SetBackgroundColor(string color) + { + try + { + // 这里需要调用设置背景颜色的方法 + LogHelper.WriteLogToFile($"设置背景颜色: {color}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"设置背景颜色时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + #endregion + + #region 文件操作 + + public void SaveCanvas(string filePath) + { + try + { + // 这里需要调用保存画布的方法 + LogHelper.WriteLogToFile($"保存画布到: {filePath}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"保存画布时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void LoadCanvas(string filePath) + { + try + { + // 这里需要调用加载画布的方法 + LogHelper.WriteLogToFile($"加载画布从: {filePath}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"加载画布时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void ExportAsImage(string filePath, string format) + { + try + { + // 这里需要调用导出为图片的方法 + LogHelper.WriteLogToFile($"导出为图片: {filePath} ({format})"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"导出为图片时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void ExportAsPDF(string filePath) + { + try + { + // 这里需要调用导出为PDF的方法 + LogHelper.WriteLogToFile($"导出为PDF: {filePath}"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"导出为PDF时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + #endregion + + #region 编辑操作 + + public void Undo() + { + try + { + _mainWindow?.PluginHost_Undo(); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"撤销操作时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void Redo() + { + try + { + _mainWindow?.PluginHost_Redo(); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"重做操作时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void SelectAll() + { + try + { + // 这里需要调用全选的方法 + LogHelper.WriteLogToFile("全选"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"全选时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void DeselectAll() + { + try + { + // 这里需要调用取消选择的方法 + LogHelper.WriteLogToFile("取消选择"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"取消选择时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void DeleteSelected() + { + try + { + // 这里需要调用删除选中项的方法 + LogHelper.WriteLogToFile("删除选中项"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"删除选中项时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void CopySelected() + { + try + { + // 这里需要调用复制选中项的方法 + LogHelper.WriteLogToFile("复制选中项"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"复制选中项时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void CutSelected() + { + try + { + // 这里需要调用剪切选中项的方法 + LogHelper.WriteLogToFile("剪切选中项"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"剪切选中项时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void Paste() + { + try + { + // 这里需要调用粘贴的方法 + LogHelper.WriteLogToFile("粘贴"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"粘贴时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + #endregion + + #region 事件系统 + + public void RegisterEventHandler(string eventName, EventHandler handler) + { + try + { + if (!_eventHandlers.ContainsKey(eventName)) + { + _eventHandlers[eventName] = handler; + } + else + { + _eventHandlers[eventName] += handler; + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"注册事件处理器时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void UnregisterEventHandler(string eventName, EventHandler handler) + { + try + { + if (_eventHandlers.ContainsKey(eventName)) + { + _eventHandlers[eventName] -= handler; + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"注销事件处理器时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void TriggerEvent(string eventName, object sender, EventArgs args) + { + try + { + if (_eventHandlers.ContainsKey(eventName)) + { + _eventHandlers[eventName]?.Invoke(sender, args); + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"触发事件时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + #endregion + + #region 应用程序操作 + + public void RestartApplication() + { + try + { + var path = Process.GetCurrentProcess().MainModule?.FileName; + if (!string.IsNullOrEmpty(path)) + { + Process.Start(new ProcessStartInfo + { + FileName = path, + UseShellExecute = true + }); + } + + Application.Current?.Shutdown(0); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"重启应用程序时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void ExitApplication() + { + try + { + Application.Current?.Shutdown(0); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"退出应用程序时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void CheckForUpdates() + { + try + { + // 这里需要调用检查更新的方法 + LogHelper.WriteLogToFile("检查更新"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"检查更新时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void OpenHelpDocument() + { + try + { + // 这里需要调用打开帮助文档的方法 + LogHelper.WriteLogToFile("打开帮助文档"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"打开帮助文档时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + public void OpenAboutPage() + { + try + { + // 这里需要调用打开关于页面的方法 + LogHelper.WriteLogToFile("打开关于页面"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"打开关于页面时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + #endregion + + #region 私有方法 - 获取当前状态 + + private int GetCurrentDrawingMode() + { + // 这里需要根据实际的绘制模式状态来实现 + return 0; + } + + private double GetCurrentInkWidth() + { + // 这里需要根据实际的墨迹宽度状态来实现 + return 2.5; + } + + private Color GetCurrentInkColor() + { + // 这里需要根据实际的墨迹颜色状态来实现 + return Colors.Black; + } + + private double GetCurrentHighlighterWidth() + { + // 这里需要根据实际的高亮笔宽度状态来实现 + return 20.0; + } + + private int GetCurrentEraserSize() + { + // 这里需要根据实际的橡皮擦大小状态来实现 + return 2; + } + + private int GetCurrentEraserType() + { + // 这里需要根据实际的橡皮擦类型状态来实现 + return 0; + } + + private int GetCurrentEraserShape() + { + // 这里需要根据实际的橡皮擦形状状态来实现 + return 0; + } + + private double GetCurrentInkAlpha() + { + // 这里需要根据实际的墨迹透明度状态来实现 + return 255.0; + } + + private int GetCurrentInkStyle() + { + // 这里需要根据实际的墨迹样式状态来实现 + return 0; + } + + private string GetCurrentBackgroundColor() + { + // 这里需要根据实际的背景颜色状态来实现 + return "#162924"; + } + + private bool GetIsDarkTheme() + { + // 这里需要根据实际的主题状态来实现 + return false; + } + + private bool GetIsWhiteboardMode() + { + // 这里需要根据实际的白板模式状态来实现 + return false; + } + + private bool GetIsPPTMode() + { + // 这里需要根据实际的PPT模式状态来实现 + return false; + } + + private bool GetIsFullScreenMode() + { + // 这里需要根据实际的全屏模式状态来实现 + return false; + } + + private bool GetIsCanvasMode() + { + // 这里需要根据实际的画布模式状态来实现 + return true; + } + + private bool GetIsSelectionMode() + { + // 这里需要根据实际的选择模式状态来实现 + return false; + } + + private bool GetIsEraserMode() + { + // 这里需要根据实际的橡皮擦模式状态来实现 + return false; + } + + private bool GetIsShapeDrawingMode() + { + // 这里需要根据实际的形状绘制模式状态来实现 + return false; + } + + private bool GetIsHighlighterMode() + { + // 这里需要根据实际的高亮笔模式状态来实现 + return false; + } + + private bool GetCanUndo() + { + return _mainWindow?.PluginHost_CanUndo() ?? false; + } + + private bool GetCanRedo() + { + return _mainWindow?.PluginHost_CanRedo() ?? false; + } + + #endregion + + #region IPluginService / IGetService 显式实现 + + List IGetService.GetAllPlugins() + { + return PluginManager.Instance.Plugins.ToList(); + } + + IPlugin IGetService.GetPlugin(string pluginName) + { + return PluginManager.Instance.Plugins.FirstOrDefault(p => p.Name == pluginName); + } + + List IGetService.AllCanvasPages + { + get + { + var pages = AllCanvasPages; + return pages == null ? new List() : pages.ToList(); + } + } + + global::System.Windows.Controls.InkCanvas IGetService.CurrentCanvas => CurrentCanvas; + + void IWindowService.ShowNotification(string message, LegacyNotificationType type) + { + ShowNotification(message, MapLegacyNotification(type)); + } + + private static InkCanvasForClass.PluginSdk.NotificationType MapLegacyNotification(LegacyNotificationType type) + { + switch (type) + { + case LegacyNotificationType.Success: + return InkCanvasForClass.PluginSdk.NotificationType.Success; + case LegacyNotificationType.Warning: + return InkCanvasForClass.PluginSdk.NotificationType.Warning; + case LegacyNotificationType.Error: + return InkCanvasForClass.PluginSdk.NotificationType.Error; + default: + return InkCanvasForClass.PluginSdk.NotificationType.Info; + } + } + + #endregion + } +} diff --git a/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs b/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs index 9975998e..cb2cb2ef 100644 --- a/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs +++ b/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs @@ -1,509 +1,24 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; namespace Ink_Canvas.Helpers.Plugins { /// - /// 插件服务管理器,实现IPluginService接口,提供对软件内部功能的访问 + /// 兼容旧代码的薄门面:与 为同一实例,实现 。 /// - public class PluginServiceManager : IPluginService + public static class PluginServiceManager { - private static PluginServiceManager _instance; - private MainWindow _mainWindow; - private Dictionary _eventHandlers; - - /// - /// 单例实例 - /// - public static PluginServiceManager Instance + public static IPluginService Instance { get { - if (_instance == null) + var ctx = PluginRuntime.SdkContext; + if (ctx == null) { - _instance = new PluginServiceManager(); + throw new InvalidOperationException("插件宿主尚未初始化:请先调用 PluginRuntime.Initialize(MainWindow)。"); } - return _instance; + + return (IPluginService)ctx; } } - - private PluginServiceManager() - { - _eventHandlers = new Dictionary(); - } - - /// - /// 设置主窗口引用 - /// - /// 主窗口实例 - public void SetMainWindow(MainWindow mainWindow) - { - _mainWindow = mainWindow; - } - - #region 窗口和UI访问 - - public Window MainWindow => _mainWindow; - - public InkCanvas CurrentCanvas => null; // 暂时返回null,避免访问权限问题 - - public List AllCanvasPages => new List(); // 暂时返回空列表 - - public int CurrentPageIndex => 0; // 暂时返回0 - - public int TotalPageCount => 0; // 暂时返回0 - - public FrameworkElement FloatingToolBar => _mainWindow?.ViewboxFloatingBar; - - public FrameworkElement LeftPanel => _mainWindow?.BlackboardLeftSide; - - public FrameworkElement RightPanel => _mainWindow?.BlackboardRightSide; - - public FrameworkElement TopPanel => _mainWindow?.BorderTools; - - public FrameworkElement BottomPanel => _mainWindow?.BorderSettings; - - #endregion - - #region 绘制工具状态 - - public int CurrentDrawingMode => 0; // 暂时返回0 - - public double CurrentInkWidth => 2.5; // 暂时返回默认值 - - public Color CurrentInkColor => Colors.Black; // 暂时返回默认值 - - public double CurrentHighlighterWidth => 20.0; // 暂时返回默认值 - - public int CurrentEraserSize => 2; // 暂时返回默认值 - - public int CurrentEraserType => 0; // 暂时返回默认值 - - public int CurrentEraserShape => 0; // 暂时返回默认值 - - public double CurrentInkAlpha => 255.0; // 暂时返回默认值 - - public int CurrentInkStyle => 0; // 暂时返回默认值 - - public string CurrentBackgroundColor => "#162924"; // 暂时返回默认值 - - #endregion - - #region 应用状态 - - public bool IsDarkTheme => false; // 暂时返回默认值 - - public bool IsWhiteboardMode => false; // 暂时返回默认值 - - public bool IsPPTMode => false; // 暂时返回默认值 - - public bool IsFullScreenMode => false; // 暂时返回默认值 - - public bool IsCanvasMode => true; // 暂时返回默认值 - - public bool IsSelectionMode => false; // 暂时返回默认值 - - public bool IsEraserMode => false; // 暂时返回默认值 - - public bool IsShapeDrawingMode => false; // 暂时返回默认值 - - public bool IsHighlighterMode => false; // 暂时返回默认值 - - #endregion - - #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() - { - // 暂时不实现,避免访问权限问题 - } - - public void ClearAllCanvases() - { - // 暂时不实现,避免访问权限问题 - } - - public void AddNewPage() - { - // 暂时不实现,避免访问权限问题 - } - - public void DeleteCurrentPage() - { - // 暂时不实现,避免访问权限问题 - } - - public void SwitchToPage(int pageIndex) - { - // 暂时不实现,避免访问权限问题 - } - - public void NextPage() - { - // 暂时不实现,避免访问权限问题 - } - - public void PreviousPage() - { - // 暂时不实现,避免访问权限问题 - } - - public void SetDrawingMode(int mode) - { - // 暂时不实现,避免访问权限问题 - } - - public void SetInkWidth(double width) - { - // 暂时不实现,避免访问权限问题 - } - - public void SetInkColor(Color color) - { - // 暂时不实现,避免访问权限问题 - } - - public void SetHighlighterWidth(double width) - { - // 暂时不实现,避免访问权限问题 - } - - public void SetEraserSize(int size) - { - // 暂时不实现,避免访问权限问题 - } - - public void SetEraserType(int type) - { - // 暂时不实现,避免访问权限问题 - } - - public void SetEraserShape(int shape) - { - // 暂时不实现,避免访问权限问题 - } - - public void SetInkAlpha(double alpha) - { - // 暂时不实现,避免访问权限问题 - } - - public void SetInkStyle(int style) - { - // 暂时不实现,避免访问权限问题 - } - - public void SetBackgroundColor(string color) - { - // 暂时不实现,避免访问权限问题 - } - - public void SaveCanvas(string filePath) - { - // 暂时不实现,避免访问权限问题 - } - - public void LoadCanvas(string filePath) - { - // 暂时不实现,避免访问权限问题 - } - - public void ExportAsImage(string filePath, string format) - { - // 暂时不实现,避免访问权限问题 - } - - public void ExportAsPDF(string filePath) - { - // 暂时不实现,避免访问权限问题 - } - - public void Undo() - { - // 暂时不实现,避免访问权限问题 - } - - public void Redo() - { - // 暂时不实现,避免访问权限问题 - } - - public void SelectAll() - { - // 暂时不实现,避免访问权限问题 - } - - public void DeselectAll() - { - // 暂时不实现,避免访问权限问题 - } - - public void DeleteSelected() - { - // 暂时不实现,避免访问权限问题 - } - - public void CopySelected() - { - // 暂时不实现,避免访问权限问题 - } - - public void CutSelected() - { - // 暂时不实现,避免访问权限问题 - } - - public void Paste() - { - // 暂时不实现,避免访问权限问题 - } - - public void SetSetting(string key, T value) - { - // 暂时不实现,避免访问权限问题 - } - - public void SaveSettings() - { - // 暂时不实现,避免访问权限问题 - } - - public void LoadSettings() - { - // 暂时不实现,避免访问权限问题 - } - - public void ResetSettings() - { - // 暂时不实现,避免访问权限问题 - } - - public void EnablePlugin(string pluginName) - { - var plugin = GetPlugin(pluginName); - if (plugin != null) - { - PluginManager.Instance.TogglePlugin(plugin, true); - } - } - - public void DisablePlugin(string pluginName) - { - var plugin = GetPlugin(pluginName); - if (plugin != null) - { - PluginManager.Instance.TogglePlugin(plugin, false); - } - } - - public void UnloadPlugin(string pluginName) - { - var plugin = GetPlugin(pluginName); - if (plugin != null) - { - PluginManager.Instance.UnloadPlugin(plugin); - } - } - - public void RegisterEventHandler(string eventName, EventHandler handler) - { - if (!_eventHandlers.ContainsKey(eventName)) - { - _eventHandlers[eventName] = handler; - } - else - { - _eventHandlers[eventName] += handler; - } - } - - public void UnregisterEventHandler(string eventName, EventHandler handler) - { - if (_eventHandlers.ContainsKey(eventName)) - { - _eventHandlers[eventName] -= handler; - } - } - - public void TriggerEvent(string eventName, object sender, EventArgs args) - { - if (_eventHandlers.ContainsKey(eventName)) - { - _eventHandlers[eventName]?.Invoke(sender, args); - } - } - - public void RestartApplication() - { - // 暂时不实现,避免访问权限问题 - } - - public void ExitApplication() - { - // 暂时不实现,避免访问权限问题 - } - - public void CheckForUpdates() - { - // 暂时不实现,避免访问权限问题 - } - - public void OpenHelpDocument() - { - // 暂时不实现,避免访问权限问题 - } - - public void OpenAboutPage() - { - // 暂时不实现,避免访问权限问题 - } - - #endregion } -} \ No newline at end of file +} diff --git a/Ink Canvas/Helpers/Plugins/PluginTemplate.cs b/Ink Canvas/Helpers/Plugins/PluginTemplate.cs deleted file mode 100644 index bd6979d8..00000000 --- a/Ink Canvas/Helpers/Plugins/PluginTemplate.cs +++ /dev/null @@ -1,276 +0,0 @@ -using System; -using System.Windows; -using System.Windows.Controls; - -namespace Ink_Canvas.Helpers.Plugins -{ - /// - /// 插件模板,用于开发者参考 - /// 注意:实际开发时,请将此类移到单独的程序集中 - /// - public class PluginTemplate : PluginBase - { - #region 插件基本信息 - - /// - /// 插件名称 - /// - public override string Name => "插件模板"; - - /// - /// 插件描述 - /// - public override string Description => "这是一个插件开发模板,用于开发者参考。"; - - /// - /// 插件版本 - /// - public override Version Version => new Version(1, 0, 0); - - /// - /// 插件作者 - /// - public override string Author => "Your Name"; - - /// - /// 是否为内置插件(外部插件请返回false) - /// - public override bool IsBuiltIn => false; - - #endregion - - #region 插件生命周期 - - /// - /// 插件初始化 - /// 在这里进行插件的初始化工作,如加载配置、注册事件等 - /// - public override void Initialize() - { - // 先调用基类方法,这样会设置插件ID和记录日志 - base.Initialize(); - - // TODO: 在这里进行插件初始化工作 - - // 示例:记录初始化信息 - LogHelper.WriteLogToFile($"插件 {Name} 开始初始化"); - - // 示例:加载配置 - LoadConfig(); - - // 示例:注册自定义事件 - // MainWindow.Instance.SomeEvent += OnSomeEvent; - - LogHelper.WriteLogToFile($"插件 {Name} 初始化完成"); - } - - /// - /// 启用插件 - /// 在这里激活插件功能 - /// - public override void Enable() - { - // 先调用基类方法,这样会设置插件状态和记录日志 - base.Enable(); - - // TODO: 在这里启用插件功能 - - LogHelper.WriteLogToFile($"插件 {Name} 已启用"); - } - - /// - /// 禁用插件 - /// 在这里停用插件功能 - /// - public override void Disable() - { - // 先调用基类方法,这样会设置插件状态和记录日志 - base.Disable(); - - // TODO: 在这里禁用插件功能 - - LogHelper.WriteLogToFile($"插件 {Name} 已禁用"); - } - - /// - /// 清理资源 - /// 在插件卸载时调用,清理资源 - /// - public override void Cleanup() - { - // TODO: 在这里清理插件资源 - - // 示例:取消注册事件 - // MainWindow.Instance.SomeEvent -= OnSomeEvent; - - // 示例:保存配置 - SaveConfig(); - - // 最后调用基类方法 - base.Cleanup(); - } - - #endregion - - #region 插件配置 - - /// - /// 加载插件配置 - /// - private void LoadConfig() - { - try - { - // TODO: 从文件或其他位置加载配置 - // 示例: - // string configPath = Path.Combine(App.RootPath, "PluginConfigs", "YourPluginName.json"); - // if (File.Exists(configPath)) - // { - // string json = File.ReadAllText(configPath); - // YourConfig = Newtonsoft.Json.JsonConvert.DeserializeObject(json); - // } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"加载插件配置时出错: {ex.Message}", LogHelper.LogType.Error); - } - } - - /// - /// 保存插件配置 - /// - private void SaveConfig() - { - try - { - // TODO: 保存配置到文件或其他位置 - // 示例: - // string configDir = Path.Combine(App.RootPath, "PluginConfigs"); - // if (!Directory.Exists(configDir)) - // { - // Directory.CreateDirectory(configDir); - // } - // string configPath = Path.Combine(configDir, "YourPluginName.json"); - // string json = Newtonsoft.Json.JsonConvert.SerializeObject(YourConfig, Newtonsoft.Json.Formatting.Indented); - // File.WriteAllText(configPath, json); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"保存插件配置时出错: {ex.Message}", LogHelper.LogType.Error); - } - } - - #endregion - - #region 插件设置界面 - - /// - /// 获取插件设置界面 - /// - /// 插件设置界面 - public override UserControl GetSettingsView() - { - // 创建插件设置界面 - return new PluginTemplateSettingsControl(); - } - - #endregion - - #region 插件功能方法 - - // TODO: 在这里添加插件的具体功能方法 - - /// - /// 示例方法:执行一些功能 - /// - public void DoSomething() - { - if (!IsEnabled) return; - - try - { - // TODO: 实现你的功能 - MessageBox.Show("插件功能执行示例", "插件模板", MessageBoxButton.OK, MessageBoxImage.Information); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"执行插件功能时出错: {ex.Message}", LogHelper.LogType.Error); - } - } - - #endregion - } - - /// - /// 插件设置控件 - /// - public class PluginTemplateSettingsControl : UserControl - { - public PluginTemplateSettingsControl() - { - // 创建设置界面布局 - var panel = new StackPanel - { - Margin = new Thickness(10) - }; - - // 添加标题 - panel.Children.Add(new TextBlock - { - Text = "插件模板设置", - FontSize = 16, - FontWeight = FontWeights.Bold, - Margin = new Thickness(0, 0, 0, 10) - }); - - // 添加说明文字 - panel.Children.Add(new TextBlock - { - Text = "这是一个示例设置界面,你可以在这里添加自己的设置控件。", - TextWrapping = TextWrapping.Wrap, - Margin = new Thickness(0, 0, 0, 15) - }); - - // 添加示例设置选项 - var checkBox = new CheckBox - { - Content = "启用某项功能", - Margin = new Thickness(0, 0, 0, 10) - }; - panel.Children.Add(checkBox); - - // 添加文本输入框 - panel.Children.Add(new TextBlock - { - Text = "设置项:", - Margin = new Thickness(0, 5, 0, 5) - }); - - panel.Children.Add(new TextBox - { - Margin = new Thickness(0, 0, 0, 10), - Width = 200, - HorizontalAlignment = HorizontalAlignment.Left - }); - - // 添加按钮 - var button = new Button - { - Content = "保存设置", - Padding = new Thickness(10, 5, 10, 5), - Margin = new Thickness(0, 10, 0, 0), - HorizontalAlignment = HorizontalAlignment.Left - }; - - button.Click += (sender, e) => - { - MessageBox.Show("设置已保存!", "插件模板", MessageBoxButton.OK, MessageBoxImage.Information); - }; - - panel.Children.Add(button); - - // 设置控件内容 - Content = panel; - } - } -} \ No newline at end of file diff --git a/Ink Canvas/Helpers/Plugins/SdkPluginAdapter.cs b/Ink Canvas/Helpers/Plugins/SdkPluginAdapter.cs new file mode 100644 index 00000000..11e20961 --- /dev/null +++ b/Ink Canvas/Helpers/Plugins/SdkPluginAdapter.cs @@ -0,0 +1,133 @@ +using System; +using System.Windows.Controls; +using InkCanvasForClass.PluginHost; +using InkCanvasForClass.PluginSdk; + +namespace Ink_Canvas.Helpers.Plugins +{ + /// + /// 将基于 的外部插件适配为宿主统一的 。 + /// + public sealed class SdkPluginAdapter : PluginBase + { + private readonly IInkCanvasPlugin _core; + private readonly string _folderId; + + public SdkPluginAdapter(string folderId, IInkCanvasPlugin core, string mainAssemblyPath) + { + _folderId = folderId ?? throw new ArgumentNullException(nameof(folderId)); + _core = core ?? throw new ArgumentNullException(nameof(core)); + PluginPath = mainAssemblyPath ?? string.Empty; + } + + public string FolderId => _folderId; + + public IInkCanvasPlugin Core => _core; + + public override string PluginStateKey => "SdkFolder:" + _folderId; + + public override string Name => _core.Name; + + public override string Description => _core.Description; + + public override Version Version => _core.Version; + + public override string Author => _core.Author; + + public override bool IsBuiltIn => false; + + public override void Initialize() + { + base.Initialize(); + + var ctx = PluginRuntime.SdkContext; + if (ctx == null) + { + LogHelper.WriteLogToFile($"SDK 插件 {_core.Name} 初始化失败:宿主上下文未就绪", LogHelper.LogType.Error); + return; + } + + _core.Initialize(ctx); + + var registry = PluginManager.Instance.ExtensionRegistry; + registry.SetCurrentPluginId(_folderId); + try + { + if (_core is InkCanvasPluginBase pluginBase) + { + pluginBase.RegisterExtensions(registry); + } + } + finally + { + registry.SetCurrentPluginId(string.Empty); + } + } + + public override void Enable() + { + if (IsEnabled) + { + return; + } + + if (_core is InkCanvasPluginBase b) + { + b.IsEnabled = true; + } + else + { + _core.Start(); + } + + base.Enable(); + } + + public override void Disable() + { + if (!IsEnabled) + { + return; + } + + if (_core is InkCanvasPluginBase b) + { + b.IsEnabled = false; + } + else + { + _core.Stop(); + } + + base.Disable(); + } + + public override UserControl GetSettingsView() + { + return _core.GetSettingsView(); + } + + public override void Cleanup() + { + try + { + if (_core is InkCanvasPluginBase b) + { + b.IsEnabled = false; + } + else + { + _core.Stop(); + } + + _core.Cleanup(); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"SDK 插件 {_core.Name} Cleanup 出错: {ex.Message}", LogHelper.LogType.Error); + } + + base.Cleanup(); + } + } +} diff --git a/Ink Canvas/Helpers/TimeMachine.cs b/Ink Canvas/Helpers/TimeMachine.cs index 58b9c546..492c96cc 100644 --- a/Ink Canvas/Helpers/TimeMachine.cs +++ b/Ink Canvas/Helpers/TimeMachine.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Windows; using System.Windows.Ink; @@ -140,6 +140,12 @@ namespace Ink_Canvas.Helpers OnUndoStateChanged?.Invoke(_currentIndex > -1); OnRedoStateChanged?.Invoke(_currentStrokeHistory.Count - _currentIndex - 1 > 0); } + + /// 当前历史是否允许撤销。 + public bool CanUndo => _currentIndex > -1; + + /// 当前历史是否允许重做。 + public bool CanRedo => _currentStrokeHistory.Count > 0 && _currentStrokeHistory.Count - _currentIndex - 1 > 0; } public class TimeMachineHistory diff --git a/Ink Canvas/InkCanvasForClass.csproj b/Ink Canvas/InkCanvasForClass.csproj index 47bdc078..962ca671 100644 --- a/Ink Canvas/InkCanvasForClass.csproj +++ b/Ink Canvas/InkCanvasForClass.csproj @@ -157,6 +157,10 @@ + + + + {F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs index 6d40b4e6..993c8517 100644 --- a/Ink Canvas/MainWindow.xaml.cs +++ b/Ink Canvas/MainWindow.xaml.cs @@ -80,6 +80,12 @@ namespace Ink_Canvas public int BoothResolutionWidth => _boothResolutionWidth; public int BoothResolutionHeight => _boothResolutionHeight; + /// 供插件系统访问的白板页面列表(只读)。 + public IList WhiteboardPages => whiteboardPages; + + /// 供插件系统访问的当前页索引。 + public int CurrentPageIndex => currentPageIndex; + private static Cursor _cachedPenCursor = null; private static readonly object _cursorLock = new object(); @@ -2824,7 +2830,7 @@ namespace Ink_Canvas { try { - // 初始化插件管理器 + PluginRuntime.Initialize(this); PluginManager.Instance.Initialize(); LogHelper.WriteLogToFile("插件系统已初始化"); } diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs index e3c1f7e2..b761d751 100644 --- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs +++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs @@ -370,7 +370,7 @@ namespace Ink_Canvas /// /// 是否自動居中浮動工具欄 /// - private async void HideSubPanels(string mode = null, bool autoAlignCenter = false) + internal async void HideSubPanels(string mode = null, bool autoAlignCenter = false) { AnimationsHelper.HideWithSlideAndFade(BorderTools); AnimationsHelper.HideWithSlideAndFade(BoardBorderTools); @@ -3177,7 +3177,7 @@ namespace Ink_Canvas /// /// 发送者 /// 路由事件参数 - private async void BtnSettings_Click(object sender, RoutedEventArgs e) + internal async void BtnSettings_Click(object sender, RoutedEventArgs e) { if (BorderSettings.Visibility == Visibility.Visible) { diff --git a/Ink Canvas/MainWindow_cs/MainWindow_PluginHostApi.cs b/Ink Canvas/MainWindow_cs/MainWindow_PluginHostApi.cs new file mode 100644 index 00000000..b94ad59a --- /dev/null +++ b/Ink Canvas/MainWindow_cs/MainWindow_PluginHostApi.cs @@ -0,0 +1,152 @@ +using System; +using System.Windows; +using System.Windows.Ink; +using MessageBox = iNKORE.UI.WPF.Modern.Controls.MessageBox; + +namespace Ink_Canvas +{ + /// + /// 供 调用的宿主 API,封装 UI 线程与内部墨迹逻辑。 + /// + public partial class MainWindow : Window + { + internal void PluginHost_RunOnUiThread(Action action) + { + if (action == null) + { + return; + } + + if (Dispatcher.CheckAccess()) + { + action(); + } + else + { + Dispatcher.Invoke(action); + } + } + + internal void PluginHost_Undo() + { + PluginHost_RunOnUiThread(() => + { + if (inkCanvas.GetSelectedStrokes().Count != 0) + { + GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed; + inkCanvas.Select(new StrokeCollection()); + } + + var item = timeMachine.Undo(); + ApplyHistoryToCanvas(item); + }); + } + + internal void PluginHost_Redo() + { + PluginHost_RunOnUiThread(() => + { + if (inkCanvas.GetSelectedStrokes().Count != 0) + { + GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed; + inkCanvas.Select(new StrokeCollection()); + } + + var item = timeMachine.Redo(); + ApplyHistoryToCanvas(item); + }); + } + + internal void PluginHost_ClearInk(bool erasedByCode) + { + PluginHost_RunOnUiThread(() => ClearStrokes(erasedByCode)); + } + + internal bool PluginHost_CanUndo() + { + if (Dispatcher.CheckAccess()) + { + return timeMachine != null && timeMachine.CanUndo; + } + + return Dispatcher.Invoke(() => timeMachine != null && timeMachine.CanUndo); + } + + internal bool PluginHost_CanRedo() + { + if (Dispatcher.CheckAccess()) + { + return timeMachine != null && timeMachine.CanRedo; + } + + return Dispatcher.Invoke(() => timeMachine != null && timeMachine.CanRedo); + } + + internal void PluginHost_ShowInfo(string title, string message) + { + PluginHost_RunOnUiThread(() => + { + try + { + MessageBox.Show(message ?? string.Empty, title ?? string.Empty); + } + catch + { + // 忽略对话框失败,避免插件拖垮宿主 + } + }); + } + + internal bool PluginHost_ShowConfirm(string title, string message) + { + if (Dispatcher.CheckAccess()) + { + try + { + return MessageBox.Show(message ?? string.Empty, title ?? string.Empty, MessageBoxButton.YesNo) == + MessageBoxResult.Yes; + } + catch + { + return false; + } + } + + return Dispatcher.Invoke(() => + { + try + { + return MessageBox.Show(message ?? string.Empty, title ?? string.Empty, MessageBoxButton.YesNo) == + MessageBoxResult.Yes; + } + catch + { + return false; + } + }); + } + + internal string PluginHost_ShowInput(string title, string message, string defaultValue) + { + string Show() + { + try + { + return Microsoft.VisualBasic.Interaction.InputBox(message ?? string.Empty, title ?? string.Empty, + defaultValue ?? string.Empty); + } + catch + { + return defaultValue ?? string.Empty; + } + } + + if (Dispatcher.CheckAccess()) + { + return Show(); + } + + return Dispatcher.Invoke(Show); + } + } +} diff --git a/Ink Canvas/packages.lock.json b/Ink Canvas/packages.lock.json index 59fa97ac..f1e58c3c 100644 --- a/Ink Canvas/packages.lock.json +++ b/Ink Canvas/packages.lock.json @@ -230,6 +230,11 @@ "System.Memory": "4.5.4" } }, + "System.ComponentModel.Annotations": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==" + }, "System.Memory": { "type": "Transitive", "resolved": "4.5.5", @@ -330,6 +335,19 @@ "type": "Transitive", "resolved": "4.5.0", "contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==" + }, + "inkcanvas.pluginhost": { + "type": "Project", + "dependencies": { + "InkCanvas.PluginSdk": "[1.0.0, )" + } + }, + "inkcanvas.pluginsdk": { + "type": "Project", + "dependencies": { + "Newtonsoft.Json": "[13.0.3, )", + "System.ComponentModel.Annotations": "[5.0.0, )" + } } }, ".NETFramework,Version=v4.7.2/win": { diff --git a/Plugins/Host/CollectingPluginRegistry.cs b/Plugins/Host/CollectingPluginRegistry.cs new file mode 100644 index 00000000..0da5142c --- /dev/null +++ b/Plugins/Host/CollectingPluginRegistry.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Windows.Controls; +using InkCanvasForClass.PluginSdk; + +namespace InkCanvasForClass.PluginHost +{ + /// + /// 收集插件登记的菜单 / 工具栏 / 设置页,供宿主窗口在启动后统一挂载。 + /// + public sealed class CollectingPluginRegistry : IPluginRegistry + { + private string _currentPluginId = ""; + + public string CurrentPluginId => _currentPluginId; + + public ObservableCollection MenuItems { get; } = + new ObservableCollection(); + + public ObservableCollection ToolbarButtons { get; } = + new ObservableCollection(); + + public ObservableCollection SettingsPages { get; } = + new ObservableCollection(); + + public void SetCurrentPluginId(string pluginId) + { + _currentPluginId = pluginId ?? ""; + } + + public void RegisterMenuItem(string groupKey, MenuItem item) + { + if (item == null) return; + MenuItems.Add(new MenuItemRegistration(_currentPluginId, groupKey ?? "", item)); + } + + public void RegisterToolbarButton(Button button) + { + if (button == null) return; + ToolbarButtons.Add(new ToolbarButtonRegistration(_currentPluginId, button)); + } + + public void RegisterSettingsPage(string pageId, string displayName, Func createView) + { + if (string.IsNullOrWhiteSpace(pageId) || createView == null) return; + SettingsPages.Add(new SettingsPageRegistration( + _currentPluginId, + pageId, + displayName ?? pageId, + createView)); + } + + public void Clear() + { + MenuItems.Clear(); + ToolbarButtons.Clear(); + SettingsPages.Clear(); + _currentPluginId = ""; + } + } + + public sealed class MenuItemRegistration + { + public MenuItemRegistration(string pluginId, string groupKey, MenuItem item) + { + PluginId = pluginId ?? ""; + GroupKey = groupKey ?? ""; + Item = item ?? throw new ArgumentNullException(nameof(item)); + } + + public string PluginId { get; } + public string GroupKey { get; } + public MenuItem Item { get; } + } + + public sealed class ToolbarButtonRegistration + { + public ToolbarButtonRegistration(string pluginId, Button button) + { + PluginId = pluginId ?? ""; + Button = button ?? throw new ArgumentNullException(nameof(button)); + } + + public string PluginId { get; } + public Button Button { get; } + } + + public sealed class SettingsPageRegistration + { + public SettingsPageRegistration(string pluginId, string pageId, string displayName, Func createView) + { + PluginId = pluginId ?? ""; + PageId = pageId ?? ""; + DisplayName = displayName ?? ""; + CreateView = createView ?? throw new ArgumentNullException(nameof(createView)); + } + + public string PluginId { get; } + public string PageId { get; } + public string DisplayName { get; } + public Func CreateView { get; } + } +} diff --git a/Plugins/Host/InkCanvas.PluginHost.csproj b/Plugins/Host/InkCanvas.PluginHost.csproj new file mode 100644 index 00000000..6fe1ef7f --- /dev/null +++ b/Plugins/Host/InkCanvas.PluginHost.csproj @@ -0,0 +1,16 @@ + + + + net472 + true + InkCanvasForClass.PluginHost + InkCanvas.PluginHost + 7.3 + disable + + + + + + + diff --git a/Plugins/SDK/IInkCanvasPlugin.cs b/Plugins/SDK/IInkCanvasPlugin.cs new file mode 100644 index 00000000..1b36f434 --- /dev/null +++ b/Plugins/SDK/IInkCanvasPlugin.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Windows.Controls; +using System.Windows.Media; + +namespace InkCanvasForClass.PluginSdk +{ + /// + /// Ink Canvas 插件接口 + /// + public interface IInkCanvasPlugin + { + /// + /// 插件唯一标识符 + /// + string Id { get; } + + /// + /// 插件名称 + /// + string Name { get; } + + /// + /// 插件描述 + /// + string Description { get; } + + /// + /// 插件版本 + /// + Version Version { get; } + + /// + /// 插件作者 + /// + string Author { get; } + + /// + /// 插件主页URL + /// + string Homepage { get; } + + /// + /// 插件图标 + /// + ImageSource Icon { get; } + + /// + /// 插件初始化 + /// + /// 插件上下文 + void Initialize(IPluginContext context); + + /// + /// 插件启动 + /// + void Start(); + + /// + /// 插件停止 + /// + void Stop(); + + /// + /// 插件清理 + /// + void Cleanup(); + + /// + /// 获取插件设置界面 + /// + /// 设置界面控件 + UserControl GetSettingsView(); + + /// + /// 获取插件菜单项 + /// + /// 菜单项列表 + IEnumerable GetMenuItems(); + + /// + /// 获取插件工具栏按钮 + /// + /// 工具栏按钮列表 + IEnumerable