11 KiB
11 KiB
Components
基于架构模式和数据模型,系统划分为以下核心组件。每个组件负责特定功能,并通过清晰的接口与其他组件交互。
PropertyGrid
职责:自动生成属性编辑 UI,支持多种属性类型、分组、只读属性和基础验证。
关键接口:
SelectedObject(依赖属性)- 绑定的数据对象,变化时自动刷新属性列表Properties(ObservableCollection)- 解析后的属性列表PropertyValueChanged(事件)- 属性值变化时触发
依赖关系:
- 依赖 TwoColumnLayout 进行布局
- 依赖 PropertyEditors(TextBox、NumericUpDown、ComboBox 等)
- 依赖 ThemeManager 获取当前主题颜色
- 使用反射(System.Reflection)解析对象属性
技术细节:
- 继承自
TemplatedControl - 使用 ReactiveUI 的
WhenAnyValue监听 SelectedObject 变化 - 通过
PropertyInfo.GetCustomAttributes<T>()读取 Attribute(如[Category]、[Browsable]) - 编辑器选择逻辑:根据
PropertyItem.PropertyType映射到对应控件
实现示例(核心逻辑):
public class PropertyGrid : TemplatedControl
{
public static readonly StyledProperty<object?> SelectedObjectProperty =
AvaloniaProperty.Register<PropertyGrid, object?>(nameof(SelectedObject));
public object? SelectedObject
{
get => GetValue(SelectedObjectProperty);
set => SetValue(SelectedObjectProperty, value);
}
public ObservableCollection<PropertyItem> Properties { get; } = new();
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
this.GetObservable(SelectedObjectProperty)
.Subscribe(obj => RefreshProperties(obj));
}
private void RefreshProperties(object? obj)
{
Properties.Clear();
if (obj == null) return;
var properties = obj.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead)
.Select(p => CreatePropertyItem(obj, p))
.OrderBy(p => p.Category)
.ThenBy(p => p.Order);
foreach (var prop in properties)
{
Properties.Add(prop);
}
}
}
TwoColumnLayout
职责:提供"标签-编辑器"配对的布局控件,左列固定或自适应宽度,右列占据剩余空间。
关键接口:
Items(ObservableCollection)- 行集合LabelWidth(double)- 左列宽度(默认 Auto)RowSpacing(double)- 行间距(默认 8px)
依赖关系:
- 无外部依赖(纯布局控件)
- 被 PropertyGrid 使用
技术细节:
- 继承自
Panel或内部使用Grid - 重写
MeasureOverride和ArrangeOverride实现自定义布局 - 响应主题系统(标签文本颜色使用
TextSecondary)
布局逻辑:
┌─────────────────────────────────┐
│ Label 1 │ Editor 1 │
│ Label 2 │ Editor 2 │
│ Label 3 │ Editor 3 │
└─────────────────────────────────┘
← LabelWidth → ← 剩余空间 →
PropertyEditors(编辑器集合)
职责:为不同属性类型提供专用编辑器控件。
组件列表:
| 属性类型 | 编辑器控件 | 说明 |
|---|---|---|
| string | TextBox | Avalonia 内置 |
| int, double | NumericUpDown | Avalonia 内置或自定义 |
| bool | CheckBox | Avalonia 内置 |
| enum | ComboBox | 自动填充枚举值 |
| DateTime | DatePicker + TimePicker | 组合控件 |
关键接口:
- 所有编辑器实现双向绑定(TwoWay Binding)
- 支持 IsEnabled 控制只读状态
- 支持 Avalonia 的 DataValidation 机制
依赖关系:
- 被 PropertyGrid 使用
- 依赖 ThemeManager 获取主题颜色
扩展性:
- 开发者可通过
PropertyGrid.EditorTemplateSelector注册自定义编辑器
UserGuide
职责:管理多步引导流程,协调 Overlay 和引导提示框的显示。
关键接口:
Steps(ObservableCollection)- 引导步骤集合CurrentStepIndex(int)- 当前步骤索引NextStepCommand(ICommand)- 下一步命令PreviousStepCommand(ICommand)- 上一步命令SkipCommand(ICommand)- 跳过命令Completed(事件)- 引导完成事件
依赖关系:
- 依赖 Overlay 控件显示遮罩
- 依赖 RichTooltip 显示引导提示框
- 依赖 GuideStep 数据模型
技术细节:
- 继承自
ContentControl - 使用 ReactiveUI 的
ReactiveCommand实现步骤流转 - 步骤切换时触发动画(淡入淡出,200ms)
核心逻辑:
public class UserGuide : ContentControl
{
public ObservableCollection<GuideStep> Steps { get; } = new();
private int _currentStepIndex;
public ReactiveCommand<Unit, Unit> NextStepCommand { get; }
public ReactiveCommand<Unit, Unit> PreviousStepCommand { get; }
public ReactiveCommand<Unit, Unit> SkipCommand { get; }
public UserGuide()
{
NextStepCommand = ReactiveCommand.Create(() =>
{
if (_currentStepIndex < Steps.Count - 1)
{
_currentStepIndex++;
ShowCurrentStep();
}
else
{
Complete();
}
});
// ... 其他 Command 实现
}
}
Overlay
职责:在窗口上层显示半透明遮罩,可选地挖空特定控件区域以聚焦目标。
关键接口:
IsVisible(bool)- 显示/隐藏遮罩TargetControl(Control?)- 挖空目标控件BackgroundOpacity(double)- 不透明度(默认 0.5)BackgroundColor(Color)- 遮罩颜色
依赖关系:
- 被 UserGuide 使用
- 依赖 ThemeManager(暗色模式下调整遮罩颜色)
技术细节:
- 继承自
ContentControl或Panel - 使用绝对定位覆盖整个窗口
- 挖空逻辑:通过
Clip或多个Rectangle实现
视觉效果:
┌─────────────────────────────────┐
│████████████████████████████████│ ← 半透明遮罩
│████████┌──────────┐████████████│
│████████│ Target │████████████│ ← 挖空区域清晰可见
│████████└──────────┘████████████│
│████████████████████████████████│
└─────────────────────────────────┘
RichTooltip
职责:显示支持基础富文本的增强 Tooltip。
关键接口:
Content(string)- 提示内容,支持简单 Markdown 语法(**粗体**、*斜体*、\n换行)MaxWidth(double)- 最大宽度(默认 300px)
依赖关系:
- 扩展 Avalonia 的
ToolTip - 被 UserGuide 使用
技术细节:
- 内部使用
TextBlock配合Inlines(Run、Bold、Italic) - 简单的 Markdown 解析器(不依赖第三方库)
- 响应主题系统(背景色
Surface,文本色TextPrimary)
解析示例:
输入:"**注意**: 这是一个重要提示。\n请仔细阅读。"
输出:
<TextBlock>
<Bold>注意</Bold>: 这是一个重要提示。
<LineBreak />
请仔细阅读。
</TextBlock>
ThemeManager
职责:管理主题切换,提供全局主题访问接口。
关键接口:
ApplyTheme(ThemeType type)(方法)- 切换主题CurrentTheme(ThemeType)- 当前主题类型ThemeChanged(事件)- 主题变化事件
依赖关系:
- 被所有控件使用(通过静态方法或单例)
- 依赖 Avalonia 的
Application.Current.Resources
技术细节:
- 静态类或单例模式
- 主题切换通过替换
ResourceDictionary实现 - 支持动画过渡(可选,100ms 淡入淡出)
实现示例:
public static class ThemeManager
{
private static ThemeType _currentTheme = ThemeType.Light;
public static event EventHandler<ThemeType>? ThemeChanged;
public static void ApplyTheme(ThemeType type)
{
if (_currentTheme == type) return;
var app = Application.Current;
if (app == null) return;
// 移除旧主题
var oldTheme = app.Resources.MergedDictionaries
.FirstOrDefault(d => d.Source?.ToString().Contains("Theme") == true);
if (oldTheme != null)
app.Resources.MergedDictionaries.Remove(oldTheme);
// 加载新主题
var uri = type == ThemeType.Light
? new Uri("avares://Penguin.AvaloniaUI/Themes/LightTheme.axaml")
: new Uri("avares://Penguin.AvaloniaUI/Themes/DarkTheme.axaml");
var newTheme = new ResourceDictionary { Source = uri };
app.Resources.MergedDictionaries.Add(newTheme);
_currentTheme = type;
ThemeChanged?.Invoke(null, type);
}
}
Component Diagrams
graph TB
subgraph "业务控件层"
PropertyGrid[PropertyGrid]
UserGuide[UserGuide]
end
subgraph "基础控件层"
TwoColumnLayout[TwoColumnLayout]
Overlay[Overlay]
RichTooltip[RichTooltip]
Editors[PropertyEditors]
end
subgraph "工具层"
ThemeManager[ThemeManager]
end
subgraph "数据模型"
PropertyItem[PropertyItem]
GuideStep[GuideStep]
end
PropertyGrid --> TwoColumnLayout
PropertyGrid --> Editors
PropertyGrid --> PropertyItem
PropertyGrid --> ThemeManager
UserGuide --> Overlay
UserGuide --> RichTooltip
UserGuide --> GuideStep
UserGuide --> ThemeManager
TwoColumnLayout --> ThemeManager
Overlay --> ThemeManager
RichTooltip --> ThemeManager
Editors --> ThemeManager
style PropertyGrid fill:#4A90E2
style UserGuide fill:#4A90E2
style TwoColumnLayout fill:#7ED321
style Overlay fill:#7ED321
style RichTooltip fill:#7ED321
style ThemeManager fill:#F5A623