mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-23 01:44:26 +08:00
859 lines
23 KiB
Markdown
859 lines
23 KiB
Markdown
# 设置系统
|
||
|
||
本文档介绍阑山桌面的设置系统,包括配置管理、持久化、设置页面和最佳实践。
|
||
|
||
## 设置系统概览
|
||
|
||
阑山桌面提供了统一的设置系统,用于管理应用、插件和组件的配置数据。
|
||
|
||
### 核心特性
|
||
|
||
- 💾 **自动持久化** - 设置自动保存到本地
|
||
- 🔔 **变更通知** - 监听设置变更事件
|
||
- 📁 **分域管理** - 按命名空间组织设置
|
||
- 🔒 **类型安全** - 泛型 API 保证类型安全
|
||
- 🎨 **UI 集成** - 轻松创建设置页面
|
||
|
||
### 设置存储位置
|
||
|
||
```
|
||
%LOCALAPPDATA%\LanMountainDesktop\
|
||
└── settings\
|
||
├── app.json # 应用设置
|
||
├── appearance.json # 外观设置
|
||
├── plugins\
|
||
│ ├── com.example.plugin1.json
|
||
│ └── com.example.plugin2.json
|
||
└── components\
|
||
└── com.example.plugin1.component1.json
|
||
```
|
||
|
||
## 使用设置服务
|
||
|
||
### 在插件中使用
|
||
|
||
```csharp
|
||
public class MyPlugin : IPlugin
|
||
{
|
||
private IPluginContext? _context;
|
||
|
||
public async Task InitializeAsync(IPluginContext context)
|
||
{
|
||
_context = context;
|
||
|
||
// 通过 context 访问设置
|
||
var settings = context.Settings;
|
||
|
||
// 读取设置
|
||
var apiKey = settings.GetValue("ApiKey", "");
|
||
var refreshRate = settings.GetValue("RefreshRate", 60);
|
||
var enableNotifications = settings.GetValue("EnableNotifications", true);
|
||
|
||
// 保存设置
|
||
settings.SetValue("LastStartTime", DateTime.Now);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 在组件中使用
|
||
|
||
```csharp
|
||
public class MyComponent : ComponentBase
|
||
{
|
||
public override Task InitializeAsync()
|
||
{
|
||
// 组件有自己的设置域
|
||
// 自动命名空间:{PluginId}.{ComponentId}
|
||
|
||
// 读取设置
|
||
var location = Settings.GetValue("Location", "北京");
|
||
var useFahrenheit = Settings.GetValue("UseFahrenheit", false);
|
||
|
||
// 读取复杂对象
|
||
var config = Settings.GetValue<ComponentConfig>("Config", new ComponentConfig());
|
||
|
||
return Task.CompletedTask;
|
||
}
|
||
|
||
public void UpdateLocation(string location)
|
||
{
|
||
Location = location;
|
||
|
||
// 保存设置
|
||
Settings.SetValue("Location", location);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 设置 API
|
||
|
||
### ISettingsService 接口
|
||
|
||
```csharp
|
||
public interface ISettingsService
|
||
{
|
||
/// <summary>
|
||
/// 获取设置值
|
||
/// </summary>
|
||
T GetValue<T>(string key, T defaultValue);
|
||
|
||
/// <summary>
|
||
/// 设置值
|
||
/// </summary>
|
||
void SetValue<T>(string key, T value);
|
||
|
||
/// <summary>
|
||
/// 删除设置
|
||
/// </summary>
|
||
void Remove(string key);
|
||
|
||
/// <summary>
|
||
/// 检查设置是否存在
|
||
/// </summary>
|
||
bool Contains(string key);
|
||
|
||
/// <summary>
|
||
/// 获取所有键
|
||
/// </summary>
|
||
IEnumerable<string> GetAllKeys();
|
||
|
||
/// <summary>
|
||
/// 清空所有设置
|
||
/// </summary>
|
||
void Clear();
|
||
|
||
/// <summary>
|
||
/// 设置变更事件
|
||
/// </summary>
|
||
event EventHandler<SettingChangedEventArgs>? SettingChanged;
|
||
}
|
||
```
|
||
|
||
### 基本用法
|
||
|
||
```csharp
|
||
// 读取设置
|
||
var value = settings.GetValue<string>("Key", "DefaultValue");
|
||
|
||
// 保存设置
|
||
settings.SetValue("Key", "NewValue");
|
||
|
||
// 删除设置
|
||
settings.Remove("Key");
|
||
|
||
// 检查是否存在
|
||
if (settings.Contains("Key"))
|
||
{
|
||
// ...
|
||
}
|
||
|
||
// 获取所有键
|
||
var keys = settings.GetAllKeys();
|
||
|
||
// 清空所有设置
|
||
settings.Clear();
|
||
```
|
||
|
||
## 支持的数据类型
|
||
|
||
### 基本类型
|
||
|
||
```csharp
|
||
// 字符串
|
||
settings.SetValue("Name", "张三");
|
||
var name = settings.GetValue("Name", "");
|
||
|
||
// 数字
|
||
settings.SetValue("Age", 25);
|
||
var age = settings.GetValue("Age", 0);
|
||
|
||
settings.SetValue("Price", 99.99);
|
||
var price = settings.GetValue("Price", 0.0);
|
||
|
||
// 布尔值
|
||
settings.SetValue("Enabled", true);
|
||
var enabled = settings.GetValue("Enabled", false);
|
||
|
||
// 日期时间
|
||
settings.SetValue("LastUpdate", DateTime.Now);
|
||
var lastUpdate = settings.GetValue("LastUpdate", DateTime.MinValue);
|
||
|
||
// 枚举
|
||
settings.SetValue("Theme", AppTheme.Dark);
|
||
var theme = settings.GetValue("Theme", AppTheme.Light);
|
||
```
|
||
|
||
### 复杂对象
|
||
|
||
```csharp
|
||
// 定义配置类
|
||
public class WeatherConfig
|
||
{
|
||
public string City { get; set; } = "北京";
|
||
public string Unit { get; set; } = "Celsius";
|
||
public int RefreshInterval { get; set; } = 10;
|
||
public List<string> FavoriteCities { get; set; } = new();
|
||
}
|
||
|
||
// 保存对象
|
||
var config = new WeatherConfig
|
||
{
|
||
City = "上海",
|
||
Unit = "Celsius",
|
||
RefreshInterval = 15,
|
||
FavoriteCities = new List<string> { "北京", "上海", "广州" }
|
||
};
|
||
settings.SetValue("WeatherConfig", config);
|
||
|
||
// 读取对象
|
||
var savedConfig = settings.GetValue<WeatherConfig>(
|
||
"WeatherConfig",
|
||
new WeatherConfig()
|
||
);
|
||
```
|
||
|
||
### 集合类型
|
||
|
||
```csharp
|
||
// 列表
|
||
var favoriteColors = new List<string> { "红色", "蓝色", "绿色" };
|
||
settings.SetValue("FavoriteColors", favoriteColors);
|
||
var colors = settings.GetValue<List<string>>("FavoriteColors", new List<string>());
|
||
|
||
// 字典
|
||
var preferences = new Dictionary<string, string>
|
||
{
|
||
["Language"] = "zh-CN",
|
||
["Timezone"] = "Asia/Shanghai"
|
||
};
|
||
settings.SetValue("Preferences", preferences);
|
||
var prefs = settings.GetValue<Dictionary<string, string>>(
|
||
"Preferences",
|
||
new Dictionary<string, string>()
|
||
);
|
||
```
|
||
|
||
## 监听设置变更
|
||
|
||
### 订阅变更事件
|
||
|
||
```csharp
|
||
public class MyPlugin : IPlugin
|
||
{
|
||
private ISettingsService? _settings;
|
||
|
||
public async Task InitializeAsync(IPluginContext context)
|
||
{
|
||
_settings = context.Settings;
|
||
|
||
// 订阅设置变更事件
|
||
_settings.SettingChanged += OnSettingChanged;
|
||
}
|
||
|
||
private void OnSettingChanged(object? sender, SettingChangedEventArgs e)
|
||
{
|
||
// e.Key - 变更的设置键
|
||
// e.OldValue - 旧值
|
||
// e.NewValue - 新值
|
||
|
||
if (e.Key == "ApiKey")
|
||
{
|
||
var newApiKey = e.NewValue as string;
|
||
_logger.LogInformation($"API Key changed to: {newApiKey}");
|
||
|
||
// 重新初始化服务
|
||
ReinitializeService(newApiKey);
|
||
}
|
||
}
|
||
|
||
public async Task ShutdownAsync()
|
||
{
|
||
// 取消订阅(防止内存泄漏)
|
||
if (_settings != null)
|
||
{
|
||
_settings.SettingChanged -= OnSettingChanged;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 在组件中监听
|
||
|
||
```csharp
|
||
public class MyComponent : ComponentBase
|
||
{
|
||
public override Task InitializeAsync()
|
||
{
|
||
// 监听设置变更
|
||
Settings.SettingChanged += OnSettingChanged;
|
||
return Task.CompletedTask;
|
||
}
|
||
|
||
private void OnSettingChanged(object? sender, SettingChangedEventArgs e)
|
||
{
|
||
switch (e.Key)
|
||
{
|
||
case "Location":
|
||
Location = e.NewValue as string ?? "北京";
|
||
_ = RefreshWeatherAsync();
|
||
break;
|
||
|
||
case "UseFahrenheit":
|
||
UseFahrenheit = (bool)(e.NewValue ?? false);
|
||
OnPropertyChanged(nameof(DisplayTemperature));
|
||
break;
|
||
}
|
||
}
|
||
|
||
public override void Dispose()
|
||
{
|
||
// 取消订阅
|
||
Settings.SettingChanged -= OnSettingChanged;
|
||
base.Dispose();
|
||
}
|
||
}
|
||
```
|
||
|
||
## 创建设置页面
|
||
|
||
### 步骤 1: 创建设置页视图
|
||
|
||
创建 `Settings/MyPluginSettingsPage.axaml`:
|
||
|
||
```xml
|
||
<UserControl xmlns="https://github.com/avaloniaui"
|
||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||
xmlns:vm="using:MyPlugin.ViewModels"
|
||
x:Class="MyPlugin.Settings.MyPluginSettingsPage"
|
||
x:DataType="vm:MyPluginSettingsViewModel">
|
||
|
||
<ScrollViewer>
|
||
<StackPanel Spacing="16" Margin="24">
|
||
|
||
<!-- 页面标题 -->
|
||
<TextBlock Text="天气插件设置"
|
||
FontSize="24"
|
||
FontWeight="Bold"
|
||
Margin="0,0,0,8" />
|
||
|
||
<!-- 基本设置 -->
|
||
<Border Background="{DynamicResource CardBackgroundBrush}"
|
||
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
|
||
Padding="16"
|
||
BorderBrush="{DynamicResource CardBorderBrush}"
|
||
BorderThickness="1">
|
||
<StackPanel Spacing="12">
|
||
|
||
<!-- 分组标题 -->
|
||
<TextBlock Text="基本设置"
|
||
FontSize="16"
|
||
FontWeight="SemiBold" />
|
||
|
||
<!-- 城市设置 -->
|
||
<StackPanel Spacing="8">
|
||
<TextBlock Text="城市:" />
|
||
<TextBox Text="{Binding Location, Mode=TwoWay}"
|
||
Watermark="输入城市名称"
|
||
Width="300"
|
||
HorizontalAlignment="Left" />
|
||
</StackPanel>
|
||
|
||
<!-- API Key -->
|
||
<StackPanel Spacing="8">
|
||
<TextBlock Text="API Key:" />
|
||
<TextBox Text="{Binding ApiKey, Mode=TwoWay}"
|
||
Watermark="输入 API Key"
|
||
PasswordChar="●"
|
||
Width="300"
|
||
HorizontalAlignment="Left" />
|
||
<TextBlock Text="从 https://api.weather.com 获取"
|
||
FontSize="12"
|
||
Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||
</StackPanel>
|
||
|
||
</StackPanel>
|
||
</Border>
|
||
|
||
<!-- 显示设置 -->
|
||
<Border Background="{DynamicResource CardBackgroundBrush}"
|
||
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
|
||
Padding="16"
|
||
BorderBrush="{DynamicResource CardBorderBrush}"
|
||
BorderThickness="1">
|
||
<StackPanel Spacing="12">
|
||
|
||
<TextBlock Text="显示设置"
|
||
FontSize="16"
|
||
FontWeight="SemiBold" />
|
||
|
||
<!-- 温度单位 -->
|
||
<StackPanel Spacing="8">
|
||
<TextBlock Text="温度单位:" />
|
||
<ComboBox SelectedIndex="{Binding TemperatureUnitIndex, Mode=TwoWay}"
|
||
Width="200"
|
||
HorizontalAlignment="Left">
|
||
<ComboBoxItem Content="摄氏度 (°C)" />
|
||
<ComboBoxItem Content="华氏度 (°F)" />
|
||
</ComboBox>
|
||
</StackPanel>
|
||
|
||
<!-- 刷新间隔 -->
|
||
<StackPanel Spacing="8">
|
||
<TextBlock Text="刷新间隔 (分钟):" />
|
||
<NumericUpDown Value="{Binding RefreshInterval, Mode=TwoWay}"
|
||
Minimum="5"
|
||
Maximum="60"
|
||
Increment="5"
|
||
Width="200"
|
||
HorizontalAlignment="Left" />
|
||
</StackPanel>
|
||
|
||
<!-- 开关选项 -->
|
||
<CheckBox IsChecked="{Binding ShowIcon, Mode=TwoWay}"
|
||
Content="显示天气图标" />
|
||
|
||
<CheckBox IsChecked="{Binding EnableNotifications, Mode=TwoWay}"
|
||
Content="启用天气预警通知" />
|
||
|
||
</StackPanel>
|
||
</Border>
|
||
|
||
<!-- 高级设置 -->
|
||
<Border Background="{DynamicResource CardBackgroundBrush}"
|
||
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
|
||
Padding="16"
|
||
BorderBrush="{DynamicResource CardBorderBrush}"
|
||
BorderThickness="1">
|
||
<StackPanel Spacing="12">
|
||
|
||
<TextBlock Text="高级设置"
|
||
FontSize="16"
|
||
FontWeight="SemiBold" />
|
||
|
||
<!-- 收藏城市 -->
|
||
<StackPanel Spacing="8">
|
||
<TextBlock Text="收藏城市:" />
|
||
<ListBox ItemsSource="{Binding FavoriteCities}"
|
||
Height="150"
|
||
Width="300"
|
||
HorizontalAlignment="Left" />
|
||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||
<TextBox x:Name="NewCityTextBox"
|
||
Watermark="添加城市"
|
||
Width="200" />
|
||
<Button Content="添加"
|
||
Command="{Binding AddCityCommand}"
|
||
CommandParameter="{Binding #NewCityTextBox.Text}" />
|
||
</StackPanel>
|
||
</StackPanel>
|
||
|
||
</StackPanel>
|
||
</Border>
|
||
|
||
<!-- 操作按钮 -->
|
||
<StackPanel Orientation="Horizontal" Spacing="12">
|
||
<Button Content="保存"
|
||
Command="{Binding SaveCommand}"
|
||
IsDefault="True" />
|
||
<Button Content="重置"
|
||
Command="{Binding ResetCommand}" />
|
||
<Button Content="测试连接"
|
||
Command="{Binding TestConnectionCommand}" />
|
||
</StackPanel>
|
||
|
||
<!-- 状态提示 -->
|
||
<TextBlock Text="{Binding StatusMessage}"
|
||
Foreground="{Binding StatusColor}"
|
||
IsVisible="{Binding !!StatusMessage}" />
|
||
|
||
</StackPanel>
|
||
</ScrollViewer>
|
||
|
||
</UserControl>
|
||
```
|
||
|
||
### 步骤 2: 创建设置页视图模型
|
||
|
||
创建 `ViewModels/MyPluginSettingsViewModel.cs`:
|
||
|
||
```csharp
|
||
using CommunityToolkit.Mvvm.ComponentModel;
|
||
using CommunityToolkit.Mvvm.Input;
|
||
using System.Collections.ObjectModel;
|
||
|
||
namespace MyPlugin.ViewModels;
|
||
|
||
public partial class MyPluginSettingsViewModel : ObservableObject
|
||
{
|
||
private readonly ISettingsService _settings;
|
||
private readonly ILogger _logger;
|
||
|
||
public MyPluginSettingsViewModel(
|
||
ISettingsService settings,
|
||
ILogger logger)
|
||
{
|
||
_settings = settings;
|
||
_logger = logger;
|
||
|
||
// 加载设置
|
||
LoadSettings();
|
||
}
|
||
|
||
// === 属性 ===
|
||
|
||
[ObservableProperty]
|
||
private string _location = "北京";
|
||
|
||
[ObservableProperty]
|
||
private string _apiKey = "";
|
||
|
||
[ObservableProperty]
|
||
private int _temperatureUnitIndex = 0;
|
||
|
||
[ObservableProperty]
|
||
private int _refreshInterval = 10;
|
||
|
||
[ObservableProperty]
|
||
private bool _showIcon = true;
|
||
|
||
[ObservableProperty]
|
||
private bool _enableNotifications = true;
|
||
|
||
[ObservableProperty]
|
||
private ObservableCollection<string> _favoriteCities = new();
|
||
|
||
[ObservableProperty]
|
||
private string? _statusMessage;
|
||
|
||
[ObservableProperty]
|
||
private string _statusColor = "Green";
|
||
|
||
// === 命令 ===
|
||
|
||
/// <summary>
|
||
/// 保存命令
|
||
/// </summary>
|
||
[RelayCommand]
|
||
private void Save()
|
||
{
|
||
try
|
||
{
|
||
// 保存所有设置
|
||
_settings.SetValue("Location", Location);
|
||
_settings.SetValue("ApiKey", ApiKey);
|
||
_settings.SetValue("UseFahrenheit", TemperatureUnitIndex == 1);
|
||
_settings.SetValue("RefreshInterval", RefreshInterval);
|
||
_settings.SetValue("ShowIcon", ShowIcon);
|
||
_settings.SetValue("EnableNotifications", EnableNotifications);
|
||
_settings.SetValue("FavoriteCities", FavoriteCities.ToList());
|
||
|
||
ShowStatus("设置已保存", "Green");
|
||
_logger.LogInformation("Settings saved successfully");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
ShowStatus($"保存失败: {ex.Message}", "Red");
|
||
_logger.LogError(ex, "Failed to save settings");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置命令
|
||
/// </summary>
|
||
[RelayCommand]
|
||
private void Reset()
|
||
{
|
||
// 重新加载设置
|
||
LoadSettings();
|
||
ShowStatus("已重置到上次保存的值", "Orange");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加城市命令
|
||
/// </summary>
|
||
[RelayCommand]
|
||
private void AddCity(string? city)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(city))
|
||
return;
|
||
|
||
if (!FavoriteCities.Contains(city))
|
||
{
|
||
FavoriteCities.Add(city);
|
||
ShowStatus($"已添加城市: {city}", "Green");
|
||
}
|
||
else
|
||
{
|
||
ShowStatus("城市已存在", "Orange");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试连接命令
|
||
/// </summary>
|
||
[RelayCommand]
|
||
private async Task TestConnectionAsync()
|
||
{
|
||
ShowStatus("正在测试连接...", "Blue");
|
||
|
||
try
|
||
{
|
||
// 测试 API 连接
|
||
var result = await TestWeatherApiAsync(ApiKey, Location);
|
||
|
||
if (result)
|
||
{
|
||
ShowStatus("连接成功!", "Green");
|
||
}
|
||
else
|
||
{
|
||
ShowStatus("连接失败,请检查 API Key 和城市名称", "Red");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
ShowStatus($"测试失败: {ex.Message}", "Red");
|
||
_logger.LogError(ex, "Connection test failed");
|
||
}
|
||
}
|
||
|
||
// === 辅助方法 ===
|
||
|
||
private void LoadSettings()
|
||
{
|
||
Location = _settings.GetValue("Location", "北京");
|
||
ApiKey = _settings.GetValue("ApiKey", "");
|
||
|
||
var useFahrenheit = _settings.GetValue("UseFahrenheit", false);
|
||
TemperatureUnitIndex = useFahrenheit ? 1 : 0;
|
||
|
||
RefreshInterval = _settings.GetValue("RefreshInterval", 10);
|
||
ShowIcon = _settings.GetValue("ShowIcon", true);
|
||
EnableNotifications = _settings.GetValue("EnableNotifications", true);
|
||
|
||
var cities = _settings.GetValue<List<string>>("FavoriteCities", new List<string>());
|
||
FavoriteCities = new ObservableCollection<string>(cities);
|
||
}
|
||
|
||
private void ShowStatus(string message, string color)
|
||
{
|
||
StatusMessage = message;
|
||
StatusColor = color;
|
||
|
||
// 3 秒后清除状态
|
||
Task.Delay(3000).ContinueWith(_ =>
|
||
{
|
||
StatusMessage = null;
|
||
});
|
||
}
|
||
|
||
private async Task<bool> TestWeatherApiAsync(string apiKey, string location)
|
||
{
|
||
// 实际实现中测试 API 连接
|
||
await Task.Delay(1000);
|
||
return !string.IsNullOrEmpty(apiKey);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 步骤 3: 注册设置页
|
||
|
||
在插件入口注册:
|
||
|
||
```csharp
|
||
public class MyPlugin : IPlugin
|
||
{
|
||
public async Task InitializeAsync(IPluginContext context)
|
||
{
|
||
var settingsRegistry = context.Services
|
||
.GetService<ISettingsPageRegistry>();
|
||
|
||
if (settingsRegistry != null)
|
||
{
|
||
// 注册设置页
|
||
settingsRegistry.RegisterPage(
|
||
title: "天气插件",
|
||
category: "插件",
|
||
icon: "avares://MyPlugin/Assets/settings-icon.png",
|
||
pageFactory: () =>
|
||
{
|
||
var viewModel = new MyPluginSettingsViewModel(
|
||
context.Settings,
|
||
context.Logger
|
||
);
|
||
|
||
return new MyPluginSettingsPage
|
||
{
|
||
DataContext = viewModel
|
||
};
|
||
}
|
||
);
|
||
|
||
context.Logger.LogInformation("Settings page registered");
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 设置最佳实践
|
||
|
||
### ✅ 提供默认值
|
||
|
||
```csharp
|
||
// ✅ 好:提供合理的默认值
|
||
var timeout = settings.GetValue("Timeout", 30);
|
||
var apiUrl = settings.GetValue("ApiUrl", "https://api.example.com");
|
||
|
||
// ❌ 差:不提供默认值
|
||
var timeout = settings.GetValue<int>("Timeout", 0); // 0 可能不合理
|
||
```
|
||
|
||
### ✅ 验证设置值
|
||
|
||
```csharp
|
||
// ✅ 好:验证设置值
|
||
public void SetRefreshInterval(int minutes)
|
||
{
|
||
if (minutes < 1 || minutes > 60)
|
||
{
|
||
throw new ArgumentOutOfRangeException(
|
||
nameof(minutes),
|
||
"刷新间隔必须在 1-60 分钟之间"
|
||
);
|
||
}
|
||
|
||
RefreshInterval = minutes;
|
||
Settings.SetValue("RefreshInterval", minutes);
|
||
}
|
||
|
||
// ❌ 差:不验证
|
||
public void SetRefreshInterval(int minutes)
|
||
{
|
||
Settings.SetValue("RefreshInterval", minutes); // 可能是非法值
|
||
}
|
||
```
|
||
|
||
### ✅ 使用类型化配置
|
||
|
||
```csharp
|
||
// ✅ 好:使用强类型配置类
|
||
public class PluginConfig
|
||
{
|
||
public string ApiKey { get; set; } = "";
|
||
public string Location { get; set; } = "北京";
|
||
public int RefreshInterval { get; set; } = 10;
|
||
public bool EnableNotifications { get; set; } = true;
|
||
|
||
public void Validate()
|
||
{
|
||
if (string.IsNullOrEmpty(ApiKey))
|
||
throw new InvalidOperationException("API Key is required");
|
||
|
||
if (RefreshInterval < 1 || RefreshInterval > 60)
|
||
throw new ArgumentOutOfRangeException(nameof(RefreshInterval));
|
||
}
|
||
}
|
||
|
||
// 使用
|
||
var config = settings.GetValue<PluginConfig>("Config", new PluginConfig());
|
||
config.Validate();
|
||
|
||
// ❌ 差:分散的设置键
|
||
var apiKey = settings.GetValue<string>("ApiKey", "");
|
||
var location = settings.GetValue<string>("Location", "");
|
||
var interval = settings.GetValue<int>("RefreshInterval", 10);
|
||
```
|
||
|
||
### ✅ 取消事件订阅
|
||
|
||
```csharp
|
||
// ✅ 好:在 Dispose 中取消订阅
|
||
public class MyComponent : ComponentBase
|
||
{
|
||
public override Task InitializeAsync()
|
||
{
|
||
Settings.SettingChanged += OnSettingChanged;
|
||
return Task.CompletedTask;
|
||
}
|
||
|
||
public override void Dispose()
|
||
{
|
||
Settings.SettingChanged -= OnSettingChanged;
|
||
base.Dispose();
|
||
}
|
||
}
|
||
|
||
// ❌ 差:忘记取消订阅(内存泄漏)
|
||
public class MyComponent : ComponentBase
|
||
{
|
||
public override Task InitializeAsync()
|
||
{
|
||
Settings.SettingChanged += OnSettingChanged;
|
||
return Task.CompletedTask;
|
||
}
|
||
// 没有 Dispose,导致内存泄漏
|
||
}
|
||
```
|
||
|
||
## 设置迁移
|
||
|
||
### 版本升级时的设置迁移
|
||
|
||
```csharp
|
||
public class MyPlugin : IPlugin
|
||
{
|
||
public async Task InitializeAsync(IPluginContext context)
|
||
{
|
||
var settings = context.Settings;
|
||
|
||
// 检查设置版本
|
||
var settingsVersion = settings.GetValue("SettingsVersion", 1);
|
||
|
||
if (settingsVersion < 2)
|
||
{
|
||
// 迁移到版本 2
|
||
MigrateToV2(settings);
|
||
settings.SetValue("SettingsVersion", 2);
|
||
}
|
||
|
||
if (settingsVersion < 3)
|
||
{
|
||
// 迁移到版本 3
|
||
MigrateToV3(settings);
|
||
settings.SetValue("SettingsVersion", 3);
|
||
}
|
||
}
|
||
|
||
private void MigrateToV2(ISettingsService settings)
|
||
{
|
||
// 例如:重命名设置键
|
||
if (settings.Contains("OldKey"))
|
||
{
|
||
var value = settings.GetValue<string>("OldKey", "");
|
||
settings.SetValue("NewKey", value);
|
||
settings.Remove("OldKey");
|
||
}
|
||
}
|
||
|
||
private void MigrateToV3(ISettingsService settings)
|
||
{
|
||
// 例如:更改数据格式
|
||
var oldFormat = settings.GetValue<string>("Location", "");
|
||
var newFormat = new LocationConfig
|
||
{
|
||
City = oldFormat,
|
||
Country = "中国"
|
||
};
|
||
settings.SetValue("LocationConfig", newFormat);
|
||
settings.Remove("Location");
|
||
}
|
||
}
|
||
```
|
||
|
||
## 下一步
|
||
|
||
- [主题与外观](04-主题外观.md) - 适配主题系统
|
||
- [插件通信](05-插件通信.md) - 插件间协作
|
||
- [设置 API 详解](../03-API参考/04-设置API.md) - API 参考文档
|
||
- [创建设置页](../04-实战案例/04-开发设置页.md) - 实战案例
|