From 441e600b5df5e745c8e1c8557da52ce7071d9168 Mon Sep 17 00:00:00 2001 From: PrefacedCorg <1876568293@qq.com> Date: Mon, 6 Apr 2026 18:48:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=95=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Ink Canvas/Helpers/SettingsService.cs | 802 ++++++++++++++++++ Ink Canvas/Helpers/SettingsServiceDemo.cs | 75 ++ Ink Canvas/MainWindow.xaml | 142 ---- Ink Canvas/MainWindow.xaml.cs | 229 ++--- Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs | 88 +- 5 files changed, 945 insertions(+), 391 deletions(-) create mode 100644 Ink Canvas/Helpers/SettingsService.cs create mode 100644 Ink Canvas/Helpers/SettingsServiceDemo.cs diff --git a/Ink Canvas/Helpers/SettingsService.cs b/Ink Canvas/Helpers/SettingsService.cs new file mode 100644 index 00000000..53e04b1f --- /dev/null +++ b/Ink Canvas/Helpers/SettingsService.cs @@ -0,0 +1,802 @@ +using Ink_Canvas; +using Ink_Canvas.Helpers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq.Expressions; +using System.Reflection; +using System.Windows; +using UpdateChannel = Ink_Canvas.UpdateChannel; +using UpdatePackageArchitecture = Ink_Canvas.UpdatePackageArchitecture; +using TelemetryUploadLevel = Ink_Canvas.TelemetryUploadLevel; + +namespace Ink_Canvas.Services +{ + public class SettingsService + { + private static SettingsService _instance; + private static readonly object _lock = new object(); + + private Settings _settings; + private MainWindow _mainWindow; + private bool _isChangingUpdateChannelInternally = false; + private bool _isChangingUpdatePackageArchInternally = false; + + public static readonly string settingsFileName = Path.Combine("Configs", "Settings.json"); + + public event Action SettingChanged; + + public static SettingsService Instance + { + get + { + if (_instance == null) + { + lock (_lock) + { + if (_instance == null) + { + _instance = new SettingsService(); + } + } + } + return _instance; + } + } + + private SettingsService() { } + + public void Initialize(Settings settings, MainWindow mainWindow = null) + { + _settings = settings; + _mainWindow = mainWindow; + } + + public Settings Settings => _settings; + + #region Core Settings Management + + public Settings LoadSettings(bool isStartup = false, bool skipAutoUpdateCheck = false) + { + Settings loadedSettings = null; + + try + { + if (File.Exists(App.RootPath + settingsFileName)) + { + try + { + string text = File.ReadAllText(App.RootPath + settingsFileName); + loadedSettings = JsonConvert.DeserializeObject(text); + + if (loadedSettings != null) + { + CleanupObsoleteSettings(text, ref loadedSettings); + } + + if (loadedSettings == null) + { + LogHelper.WriteLogToFile("配置文件解析失败,尝试从备份恢复", LogHelper.LogType.Warning); + if (AutoBackupManager.TryRestoreFromBackup()) + { + text = File.ReadAllText(App.RootPath + settingsFileName); + loadedSettings = JsonConvert.DeserializeObject(text); + if (loadedSettings != null) + { + CleanupObsoleteSettings(text, ref loadedSettings); + } + } + + if (loadedSettings == null) + { + LogHelper.WriteLogToFile("从备份恢复失败,使用默认设置", LogHelper.LogType.Warning); + loadedSettings = new Settings(); + } + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"配置文件加载失败: {ex.Message}", LogHelper.LogType.Error); + + LogHelper.WriteLogToFile("尝试从备份恢复配置文件", LogHelper.LogType.Warning); + if (AutoBackupManager.TryRestoreFromBackup()) + { + try + { + string text = File.ReadAllText(App.RootPath + settingsFileName); + loadedSettings = JsonConvert.DeserializeObject(text); + if (loadedSettings != null) + { + CleanupObsoleteSettings(text, ref loadedSettings); + } + } + catch (Exception restoreEx) + { + LogHelper.WriteLogToFile($"从备份恢复后重新加载失败: {restoreEx.Message}", LogHelper.LogType.Error); + loadedSettings = new Settings(); + } + } + + if (loadedSettings == null) + { + LogHelper.WriteLogToFile("从备份恢复失败,使用默认设置", LogHelper.LogType.Warning); + loadedSettings = new Settings(); + } + } + } + else + { + LogHelper.WriteLogToFile("配置文件不存在,尝试从备份恢复", LogHelper.LogType.Warning); + if (AutoBackupManager.TryRestoreFromBackup()) + { + try + { + string text = File.ReadAllText(App.RootPath + settingsFileName); + loadedSettings = JsonConvert.DeserializeObject(text); + if (loadedSettings != null) + { + CleanupObsoleteSettings(text, ref loadedSettings); + } + } + catch (Exception restoreEx) + { + LogHelper.WriteLogToFile($"从备份恢复后加载失败: {restoreEx.Message}", LogHelper.LogType.Error); + loadedSettings = new Settings(); + } + } + else + { + LogHelper.WriteLogToFile("备份恢复失败,使用默认设置", LogHelper.LogType.Warning); + loadedSettings = new Settings(); + } + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile(ex.ToString(), LogHelper.LogType.Error); + loadedSettings = new Settings(); + } + + try + { + if (loadedSettings?.Appearance != null) + { + var preferredLanguage = loadedSettings.Appearance.Language ?? string.Empty; + if (!string.IsNullOrWhiteSpace(preferredLanguage)) + { + LocalizationHelper.TrySetCulture(preferredLanguage); + } + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"从配置应用界面语言失败: {ex.Message}", LogHelper.LogType.Error); + } + + try + { + ProcessProtectionManager.ApplyFromSettings(); + } + catch + { + } + + _settings = loadedSettings; + return loadedSettings; + } + + public void SaveSettingsToFile() + { + if (_settings == null) return; + + var text = JsonConvert.SerializeObject(_settings, Formatting.Indented); + try + { + string configsDir = Path.Combine(App.RootPath, "Configs"); + if (!Directory.Exists(configsDir)) + { + ProcessProtectionManager.WithWriteAccess(configsDir, () => Directory.CreateDirectory(configsDir)); + } + + var path = App.RootPath + settingsFileName; + ProcessProtectionManager.WithWriteAccess(path, () => File.WriteAllText(path, text)); + } + catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); } + } + + private void CleanupObsoleteSettings(string userConfigJson, ref Settings settings) + { + try + { + Settings defaultSettings = new Settings(); + + JObject defaultConfigObj = JObject.FromObject(defaultSettings); + EnsureDefaultConfigSchemaIncludesIgnoredNullKeys(defaultConfigObj); + JObject userConfigObj = JObject.Parse(userConfigJson); + + bool hasChanges = false; + + RemoveObsoleteProperties(userConfigObj, defaultConfigObj, ref hasChanges); + + if (hasChanges) + { + string cleanedJson = userConfigObj.ToString(Formatting.Indented); + settings = JsonConvert.DeserializeObject(cleanedJson); + SaveSettingsToFile(); + LogHelper.WriteLogToFile("已清理过期配置项", LogHelper.LogType.Event); + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"清理过期配置时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + + private static void EnsureDefaultConfigSchemaIncludesIgnoredNullKeys(JObject defaultConfigObj) + { + if (defaultConfigObj == null) return; + if (defaultConfigObj["appearance"] is JObject appearance && !appearance.ContainsKey("hitokotoCategories")) + appearance["hitokotoCategories"] = JValue.CreateNull(); + } + + private void RemoveObsoleteProperties(JObject userObj, JObject defaultObj, ref bool hasChanges) + { + if (userObj == null || defaultObj == null) + return; + + List keysToRemove = new List(); + + foreach (var property in userObj.Properties()) + { + string propertyName = property.Name; + + if (!defaultObj.ContainsKey(propertyName)) + { + keysToRemove.Add(propertyName); + continue; + } + + JToken userValue = property.Value; + JToken defaultValue = defaultObj[propertyName]; + + if (userValue != null && defaultValue != null) + { + if (userValue.Type == JTokenType.Object && defaultValue.Type == JTokenType.Object) + { + RemoveObsoleteProperties(userValue as JObject, defaultValue as JObject, ref hasChanges); + } + else if (userValue.Type == JTokenType.Array && defaultValue.Type == JTokenType.Array) + { + JArray userArray = userValue as JArray; + JArray defaultArray = defaultValue as JArray; + + if (userArray != null && defaultArray != null && userArray.Count > 0 && defaultArray.Count > 0) + { + if (userArray[0].Type == JTokenType.Object && defaultArray[0].Type == JTokenType.Object) + { + for (int i = 0; i < userArray.Count; i++) + { + if (userArray[i] is JObject userItemObj && defaultArray[0] is JObject defaultItemObj) + { + RemoveObsoleteProperties(userItemObj, defaultItemObj, ref hasChanges); + } + } + } + } + } + } + } + + foreach (var key in keysToRemove) + { + userObj.Remove(key); + hasChanges = true; + LogHelper.WriteLogToFile($"已删除过期配置项: {key}", LogHelper.LogType.Event); + } + } + + #endregion + + #region Generic Setting Methods + + public void Set(Expression> propertyExpression, T value, bool saveToFile = true) + { + if (_settings == null) return; + + var propertyName = GetPropertyName(propertyExpression); + var property = typeof(Settings).GetProperty(propertyName); + + if (property != null) + { + property.SetValue(_settings, value); + if (saveToFile) SaveSettingsToFile(); + SettingChanged?.Invoke(propertyName, value); + } + } + + public void Set(Expression> categoryExpression, Expression> propertyExpression, TProperty value, bool saveToFile = true) + { + if (_settings == null) return; + + var categoryPropertyName = GetPropertyName(categoryExpression); + var categoryProperty = typeof(Settings).GetProperty(categoryPropertyName); + + if (categoryProperty != null) + { + var categoryInstance = categoryProperty.GetValue(_settings); + if (categoryInstance != null) + { + var propertyName = GetPropertyName(propertyExpression); + var property = typeof(TCategory).GetProperty(propertyName); + + if (property != null) + { + property.SetValue(categoryInstance, value); + if (saveToFile) SaveSettingsToFile(); + SettingChanged?.Invoke($"{categoryPropertyName}.{propertyName}", value); + } + } + } + } + + public T Get(Expression> propertyExpression) + { + if (_settings == null) return default; + + var propertyName = GetPropertyName(propertyExpression); + var property = typeof(Settings).GetProperty(propertyName); + + if (property != null) + { + return (T)property.GetValue(_settings); + } + return default; + } + + public TProperty Get(Expression> categoryExpression, Expression> propertyExpression) + { + if (_settings == null) return default; + + var categoryPropertyName = GetPropertyName(categoryExpression); + var categoryProperty = typeof(Settings).GetProperty(categoryPropertyName); + + if (categoryProperty != null) + { + var categoryInstance = categoryProperty.GetValue(_settings); + if (categoryInstance != null) + { + var propertyName = GetPropertyName(propertyExpression); + var property = typeof(TCategory).GetProperty(propertyName); + + if (property != null) + { + return (TProperty)property.GetValue(categoryInstance); + } + } + } + return default; + } + + private string GetPropertyName(Expression> expression) + { + if (expression.Body is MemberExpression memberExpression) + { + return memberExpression.Member.Name; + } + throw new ArgumentException("Expression is not a property access", nameof(expression)); + } + + #endregion + + #region Convenience Methods for Common Settings + + #region Advanced Settings + + public void SetNoFocusMode(bool enabled, bool saveToFile = true) + { + Set(s => s.Advanced, a => a.IsNoFocusMode, enabled, saveToFile); + if (_mainWindow != null) + { + _mainWindow.Dispatcher.BeginInvoke(new Action(() => + { + _mainWindow.ApplyNoFocusMode(); + if (_settings.Advanced.IsAlwaysOnTop) + { + _mainWindow.ApplyAlwaysOnTop(); + } + })); + } + } + + public void SetAlwaysOnTop(bool enabled, bool saveToFile = true) + { + Set(s => s.Advanced, a => a.IsAlwaysOnTop, enabled, saveToFile); + if (_mainWindow != null) + { + _mainWindow.Dispatcher.BeginInvoke(new Action(() => + { + _mainWindow.ApplyAlwaysOnTop(); + _mainWindow.UpdateUIAccessTopMostVisibility(); + })); + } + } + + public void SetUIAccessTopMost(bool enabled, bool saveToFile = true) + { + Set(s => s.Advanced, a => a.EnableUIAccessTopMost, enabled, saveToFile); + if (_mainWindow != null) + { + _mainWindow.Dispatcher.BeginInvoke(new Action(() => + { + _mainWindow.ApplyUIAccessTopMost(); + })); + } + App.IsUIAccessTopMostEnabled = enabled; + } + + #endregion + + #region Canvas Settings + + public void SetInkFadeEnabled(bool enabled, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.EnableInkFade, enabled, saveToFile); + } + + public void SetInkFadeTime(int timeMs, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.InkFadeTime, timeMs, saveToFile); + } + + public void SetHideInkFadeControlInPenMenu(bool enabled, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.HideInkFadeControlInPenMenu, enabled, saveToFile); + } + + public void SetEraserAutoSwitchBack(bool enabled, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.EnableEraserAutoSwitchBack, enabled, saveToFile); + } + + public void SetEraserAutoSwitchBackDelay(int seconds, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.EraserAutoSwitchBackDelaySeconds, seconds, saveToFile); + } + + public void SetBrushAutoRestore(bool enabled, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.EnableBrushAutoRestore, enabled, saveToFile); + } + + public void SetBrushAutoRestoreTimes(string times, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.BrushAutoRestoreTimes, times, saveToFile); + } + + public void SetBrushAutoRestoreColor(string color, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.BrushAutoRestoreColor, color, saveToFile); + } + + public void SetBrushAutoRestoreWidth(double width, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.BrushAutoRestoreWidth, width, saveToFile); + } + + public void SetBrushAutoRestoreAlpha(int alpha, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.BrushAutoRestoreAlpha, alpha, saveToFile); + } + + public void SetInkWidth(double width, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.InkWidth, width, saveToFile); + } + + public void SetHighlighterWidth(double width, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.HighlighterWidth, width, saveToFile); + } + + public void SetInkAlpha(double alpha, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.InkAlpha, alpha, saveToFile); + } + + public void SetEraserSize(int size, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.EraserSize, size, saveToFile); + } + + public void SetEraserType(int type, bool saveToFile = true) + { + Set(s => s.Canvas, c => c.EraserType, type, saveToFile); + } + + #endregion + + #region Appearance Settings + + public void SetTheme(int themeIndex, bool saveToFile = true) + { + Set(s => s.Appearance, a => a.Theme, themeIndex, saveToFile); + } + + public void SetLanguage(string languageCode, bool saveToFile = true) + { + Set(s => s.Appearance, a => a.Language, languageCode ?? string.Empty, saveToFile); + LocalizationHelper.TrySetCulture(languageCode); + } + + public void SetFloatingBarOpacity(double opacity, bool saveToFile = true) + { + Set(s => s.Appearance, a => a.ViewboxFloatingBarOpacityValue, opacity, saveToFile); + } + + public void SetFloatingBarScale(double scale, bool saveToFile = true) + { + Set(s => s.Appearance, a => a.ViewboxFloatingBarScaleTransformValue, scale, saveToFile); + } + + #endregion + + #region PowerPoint Settings + + public void SetPPTOnlyMode(bool enabled, bool saveToFile = true) + { + Set(s => s.ModeSettings, m => m.IsPPTOnlyMode, enabled, saveToFile); + } + + public void SetPowerPointSupport(bool enabled, bool saveToFile = true) + { + Set(s => s.PowerPointSettings, p => p.PowerPointSupport, enabled, saveToFile); + } + + public void SetShowGestureButtonInSlideShow(bool enabled, bool saveToFile = true) + { + Set(s => s.PowerPointSettings, p => p.ShowGestureButtonInSlideShow, enabled, saveToFile); + } + + public void SetPPTTimeCapsuleEnabled(bool enabled, bool saveToFile = true) + { + Set(s => s.PowerPointSettings, p => p.EnablePPTTimeCapsule, enabled, saveToFile); + } + + public void SetPPTTimeCapsulePosition(int position, bool saveToFile = true) + { + Set(s => s.PowerPointSettings, p => p.PPTTimeCapsulePosition, position, saveToFile); + } + + #endregion + + #region Gesture Settings + + public void SetTwoFingerZoomEnabled(bool enabled, bool saveToFile = true) + { + Set(s => s.Gesture, g => g.IsEnableTwoFingerZoom, enabled, saveToFile); + } + + public void SetTwoFingerTranslateEnabled(bool enabled, bool saveToFile = true) + { + Set(s => s.Gesture, g => g.IsEnableTwoFingerTranslate, enabled, saveToFile); + } + + public void SetTwoFingerRotationEnabled(bool enabled, bool saveToFile = true) + { + Set(s => s.Gesture, g => g.IsEnableTwoFingerRotation, enabled, saveToFile); + } + + public void SetMultiTouchModeEnabled(bool enabled, bool saveToFile = true) + { + Set(s => s.Gesture, g => g.IsEnableMultiTouchMode, enabled, saveToFile); + } + + #endregion + + #region Startup Settings + + public void SetAutoUpdate(bool enabled, bool saveToFile = true) + { + Set(s => s.Startup, s => s.IsAutoUpdate, enabled, saveToFile); + } + + public void SetUpdateChannel(UpdateChannel channel, bool saveToFile = true) + { + Set(s => s.Startup, s => s.UpdateChannel, channel, saveToFile); + } + + public void SetTelemetryUploadLevel(TelemetryUploadLevel level, bool saveToFile = true) + { + Set(s => s.Startup, s => s.TelemetryUploadLevel, level, saveToFile); + } + + #endregion + + #region Automation Settings + + public void SetAutoSaveStrokesEnabled(bool enabled, bool saveToFile = true) + { + Set(s => s.Automation, a => a.IsEnableAutoSaveStrokes, enabled, saveToFile); + } + + public void SetAutoSaveStrokesInterval(int minutes, bool saveToFile = true) + { + Set(s => s.Automation, a => a.AutoSaveStrokesIntervalMinutes, minutes, saveToFile); + } + + public void SetAutoSavedStrokesLocation(string path, bool saveToFile = true) + { + Set(s => s.Automation, a => a.AutoSavedStrokesLocation, path, saveToFile); + } + + #endregion + + #region InkToShape Settings + + public void SetInkToShapeEnabled(bool enabled, bool saveToFile = true) + { + Set(s => s.InkToShape, i => i.IsInkToShapeEnabled, enabled, saveToFile); + } + + public void SetShapeRecognitionEngine(int engine, bool saveToFile = true) + { + Set(s => s.InkToShape, i => i.ShapeRecognitionEngine, engine, saveToFile); + } + + #endregion + + #region Security Settings + + public void SetPasswordEnabled(bool enabled, bool saveToFile = true) + { + Set(s => s.Security, s => s.PasswordEnabled, enabled, saveToFile); + } + + public void SetProcessProtectionEnabled(bool enabled, bool saveToFile = true) + { + Set(s => s.Security, s => s.EnableProcessProtection, enabled, saveToFile); + } + + #endregion + + #region Camera Settings + + public void SetCameraRotationAngle(int angle, bool saveToFile = true) + { + Set(s => s.Camera, c => c.RotationAngle, angle, saveToFile); + } + + public void SetCameraResolution(int width, int height, bool saveToFile = true) + { + Set(s => s.Camera, c => c.ResolutionWidth, width, saveToFile); + Set(s => s.Camera, c => c.ResolutionHeight, height, saveToFile); + } + + #endregion + + #endregion + + #region Startup Settings - Complete Functionality + + public bool CheckRunAtStartup() + { + try + { + return File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\Ink Canvas Annotation.lnk"); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile(ex.ToString(), LogHelper.LogType.Error); + return false; + } + } + + // Settings 中没有 IsRunAtStartup 属性,所以这个方法被注释掉了 + // public void SetRunAtStartup(bool enabled, bool saveToFile = true) + // { + // Set(s => s.Startup, s => s.IsRunAtStartup, enabled, saveToFile); + // } + + public void SetFoldAtStartup(bool enabled, bool saveToFile = true) + { + Set(s => s.Startup, s => s.IsFoldAtStartup, enabled, saveToFile); + } + + public void SetUpdatePackageArchitecture(UpdatePackageArchitecture arch, bool saveToFile = true) + { + Set(s => s.Startup, s => s.UpdatePackageArchitecture, arch, saveToFile); + } + + public void SetAutoUpdateWithSilence(bool enabled, bool saveToFile = true) + { + Set(s => s.Startup, s => s.IsAutoUpdateWithSilence, enabled, saveToFile); + } + + public void SetAutoUpdateWithSilenceStartTime(string time, bool saveToFile = true) + { + Set(s => s.Startup, s => s.AutoUpdateWithSilenceStartTime, time, saveToFile); + } + + public void SetAutoUpdateWithSilenceEndTime(string time, bool saveToFile = true) + { + Set(s => s.Startup, s => s.AutoUpdateWithSilenceEndTime, time, saveToFile); + } + + public void SetNibModeEnabled(bool enabled, bool saveToFile = true) + { + Set(s => s.Startup, s => s.IsEnableNibMode, enabled, saveToFile); + } + + public void CheckUpdateChannelAndTelemetryConsistency(bool isLoaded) + { + if (_settings == null) return; + + var currentChannel = _settings.Startup.UpdateChannel; + if (currentChannel == UpdateChannel.Release) return; + + if (!_settings.Startup.HasAcceptedTelemetryPrivacy) + { + _settings.Startup.UpdateChannel = UpdateChannel.Release; + DeviceIdentifier.UpdateUsageChannel(UpdateChannel.Release); + SaveSettingsToFile(); + LogHelper.WriteLogToFile($"启动检测 | 用户未同意隐私协议,已切换回 Release 通道"); + return; + } + + if (_settings.Startup.TelemetryUploadLevel == TelemetryUploadLevel.None) + { + _isChangingUpdateChannelInternally = true; + try + { + _settings.Startup.UpdateChannel = UpdateChannel.Release; + DeviceIdentifier.UpdateUsageChannel(UpdateChannel.Release); + SaveSettingsToFile(); + } + finally + { + _isChangingUpdateChannelInternally = false; + } + LogHelper.WriteLogToFile($"启动检测 | 用户未启用遥测,已切换回 Release 通道"); + } + } + + #endregion + + #region Helper Methods + + public static string GetThemeName(int themeIndex) + { + return themeIndex switch + { + 0 => "浅色主题", + 1 => "深色主题", + 2 => "跟随系统", + _ => "未知主题" + }; + } + + public static string GetLanguageCode(int languageIndex) + { + return languageIndex switch + { + 1 => "zh-CN", + 2 => "en-US", + _ => string.Empty + }; + } + + public static int GetLanguageIndex(string languageCode) + { + return languageCode switch + { + "zh-CN" => 1, + "en-US" => 2, + _ => 0 + }; + } + + #endregion + } +} diff --git a/Ink Canvas/Helpers/SettingsServiceDemo.cs b/Ink Canvas/Helpers/SettingsServiceDemo.cs new file mode 100644 index 00000000..dc12ae13 --- /dev/null +++ b/Ink Canvas/Helpers/SettingsServiceDemo.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Ink_Canvas; +using Ink_Canvas.Services; + +namespace Ink_Canvas +{ + public static class SettingsServiceDemo + { + public static void ListAllSettings() + { + var settingsType = typeof(Settings); + var allProperties = new List(); + + Console.WriteLine("=== Settings 所有属性列表 ===\n"); + + foreach (var categoryProp in settingsType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + if (categoryProp.PropertyType.IsClass && categoryProp.PropertyType != typeof(string) && categoryProp.PropertyType != typeof(List) && categoryProp.PropertyType != typeof(List) && categoryProp.PropertyType != typeof(List) && categoryProp.PropertyType != typeof(Dictionary) && categoryProp.PropertyType != typeof(List) && categoryProp.PropertyType != typeof(DateTime)) + { + Console.WriteLine($"\n--- 分类: {categoryProp.Name} ---\n"); + + foreach (var settingProp in categoryProp.PropertyType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + var propName = $"{categoryProp.Name}.{settingProp.Name}"; + allProperties.Add(propName); + Console.WriteLine($" {settingProp.Name,-60} ({settingProp.PropertyType.Name})"); + } + } + else + { + Console.WriteLine($"{categoryProp.Name,-60} ({categoryProp.PropertyType.Name})"); + allProperties.Add(categoryProp.Name); + } + } + + Console.WriteLine($"\n\n总计: {allProperties.Count} 个设置项\n"); + + Console.WriteLine("=== SettingsService 访问示例 ===\n"); + + Console.WriteLine("// 方式1: 泛型 Set/Get"); + Console.WriteLine("SettingsService.Instance.Set(s => s.Canvas, c => c.InkWidth, 3.5);"); + Console.WriteLine("double inkWidth = SettingsService.Instance.Get(s => s.Canvas, c => c.InkWidth);"); + Console.WriteLine(); + + Console.WriteLine("// 方式2: 便捷方法"); + Console.WriteLine("SettingsService.Instance.SetTheme(1);"); + Console.WriteLine("SettingsService.Instance.SetNoFocusMode(true);"); + Console.WriteLine(); + + Console.WriteLine("// 方式3: 直接访问 Settings 对象"); + Console.WriteLine("var settings = SettingsService.Instance.Settings;"); + Console.WriteLine("if (settings != null) {"); + Console.WriteLine(" settings.Canvas.InkWidth = 3.5;"); + Console.WriteLine(" settings.Appearance.Theme = 1;"); + Console.WriteLine(" SettingsService.Instance.Save();"); + Console.WriteLine("}"); + Console.WriteLine(); + + Console.WriteLine("// 任意设置项示例:"); + Console.WriteLine("SettingsService.Instance.Set(s => s.Automation, a => a.IsAutoFoldInEasiNote, true);"); + Console.WriteLine("SettingsService.Instance.Set(s => s.PowerPointSettings, p => p.PowerPointSupport, true);"); + Console.WriteLine("SettingsService.Instance.Set(s => s.Gesture, g => g.IsEnableTwoFingerZoom, true);"); + Console.WriteLine("SettingsService.Instance.Set(s => s.Advanced, a => a.IsAlwaysOnTop, true);"); + Console.WriteLine("SettingsService.Instance.Set(s => s.Startup, s => s.IsAutoUpdate, true);"); + Console.WriteLine("SettingsService.Instance.Set(s => s.Security, s => s.PasswordEnabled, true);"); + Console.WriteLine("SettingsService.Instance.Set(s => s.Camera, c => c.RotationAngle, 90);"); + Console.WriteLine("SettingsService.Instance.Set(s => s.InkToShape, i => i.IsInkToShapeEnabled, true);"); + Console.WriteLine("SettingsService.Instance.Set(s => s.RandSettings, r => r.EnableQuickDraw, true);"); + Console.WriteLine("SettingsService.Instance.Set(s => s.Appearance, a => a.ViewboxFloatingBarOpacityValue, 0.8);"); + } + } +} diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml index b9434bac..79fca2ae 100644 --- a/Ink Canvas/MainWindow.xaml +++ b/Ink Canvas/MainWindow.xaml @@ -655,148 +655,6 @@ Padding="15,5" Margin="0,10,0,0"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -