This commit is contained in:
PrefacedCorg
2026-04-06 18:48:31 +08:00
parent bd4b4bd233
commit 441e600b5d
5 changed files with 945 additions and 391 deletions
+802
View File
@@ -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<string, object> 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<Settings>(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<Settings>(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<Settings>(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<Settings>(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<Settings>(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<string> keysToRemove = new List<string>();
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<T>(Expression<Func<Settings, T>> 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<TCategory, TProperty>(Expression<Func<Settings, TCategory>> categoryExpression, Expression<Func<TCategory, TProperty>> 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<T>(Expression<Func<Settings, T>> 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<TCategory, TProperty>(Expression<Func<Settings, TCategory>> categoryExpression, Expression<Func<TCategory, TProperty>> 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<T, TProperty>(Expression<Func<T, TProperty>> 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
}
}
+75
View File
@@ -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<string>();
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<string>) && categoryProp.PropertyType != typeof(List<CustomFloatingBarIcon>) && categoryProp.PropertyType != typeof(List<CustomPickNameBackground>) && categoryProp.PropertyType != typeof(Dictionary<string, bool>) && categoryProp.PropertyType != typeof(List<string>) && 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);");
}
}
}