U:调整调用方式和兼容性
This commit is contained in:
1 parent
433e206d45
commit
4ec76b7855
50 files changed
+5592
-47
No files matched your search
@@ -0,0 +1,312 @@
|
||||
# 06 - 主题系统示例
|
||||
|
||||
演示如何使用 Sharp.Wpf 的主题系统实现浅色/深色主题切换,包括自定义颜色、跟随系统主题等功能。
|
||||
|
||||
## 🎯 学习目标
|
||||
|
||||
- 使用 `IThemeService` 管理应用主题
|
||||
- 实现浅色/深色主题切换
|
||||
- 自定义主题颜色
|
||||
- 跟随系统主题设置
|
||||
- 动态主题切换(无需重启)
|
||||
|
||||
## 📦 使用的模块
|
||||
|
||||
- **Sharp.Wpf** - IThemeService, ThemeService
|
||||
|
||||
## 🚀 快速运行
|
||||
|
||||
```bash
|
||||
cd examples/06-Theming
|
||||
dotnet run
|
||||
```
|
||||
|
||||
## 📝 核心代码讲解
|
||||
|
||||
### 1. App.xaml.cs - 注册主题服务
|
||||
|
||||
```csharp
|
||||
using Wpf.Theming;
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services.AddSharpWpf(); // 自动注册 IThemeService
|
||||
|
||||
services.AddViewModel<MainViewModel>();
|
||||
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
// 应用初始主题
|
||||
var themeService = provider.GetRequiredService<IThemeService>();
|
||||
themeService.ApplyTheme(Theme.Light); // 或 Theme.System
|
||||
|
||||
var mainWindow = provider.GetRequiredService<MainWindow>();
|
||||
mainWindow.Show();
|
||||
}
|
||||
```
|
||||
|
||||
### 2. MainViewModel.cs - 主题切换逻辑
|
||||
|
||||
```csharp
|
||||
using Wpf.Theming;
|
||||
|
||||
public class MainViewModel : ViewModelBase
|
||||
{
|
||||
private readonly IThemeService _themeService;
|
||||
private Theme _currentTheme;
|
||||
|
||||
public Theme CurrentTheme
|
||||
{
|
||||
get => _currentTheme;
|
||||
set
|
||||
{
|
||||
SetProperty(ref _currentTheme, value);
|
||||
_themeService.ApplyTheme(value);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand SwitchToLightCommand { get; }
|
||||
public ICommand SwitchToDarkCommand { get; }
|
||||
public ICommand SwitchToSystemCommand { get; }
|
||||
|
||||
public MainViewModel(IThemeService themeService)
|
||||
{
|
||||
_themeService = themeService;
|
||||
_currentTheme = themeService.CurrentTheme;
|
||||
|
||||
// 监听主题变化
|
||||
_themeService.ThemeChanged += (s, theme) =>
|
||||
{
|
||||
OnPropertyChanged(nameof(CurrentTheme));
|
||||
};
|
||||
|
||||
SwitchToLightCommand = new RelayCommand(() =>
|
||||
{
|
||||
CurrentTheme = Theme.Light;
|
||||
});
|
||||
|
||||
SwitchToDarkCommand = new RelayCommand(() =>
|
||||
{
|
||||
CurrentTheme = Theme.Dark;
|
||||
});
|
||||
|
||||
SwitchToSystemCommand = new RelayCommand(() =>
|
||||
{
|
||||
CurrentTheme = Theme.System;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. MainWindow.xaml - 使用主题颜色
|
||||
|
||||
```xml
|
||||
<Window x:Class="ThemingExample.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="主题系统示例" Height="500" Width="600"
|
||||
Background="{DynamicResource BackgroundColor}"> <!-- 使用主题颜色 -->
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 主题切换栏 -->
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal"
|
||||
Background="{DynamicResource PrimaryColor}" Padding="15">
|
||||
<TextBlock Text="选择主题:"
|
||||
Foreground="White" VerticalAlignment="Center" Margin="0,0,10,0"/>
|
||||
<Button Content="☀️ 浅色" Command="{Binding SwitchToLightCommand}"
|
||||
Margin="0,0,10,0" Padding="15,5"/>
|
||||
<Button Content="🌙 深色" Command="{Binding SwitchToDarkCommand}"
|
||||
Margin="0,0,10,0" Padding="15,5"/>
|
||||
<Button Content="🖥️ 跟随系统" Command="{Binding SwitchToSystemCommand}"
|
||||
Padding="15,5"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<ScrollViewer Grid.Row="1" Padding="20">
|
||||
<StackPanel>
|
||||
<TextBlock Text="主题颜色预览" FontSize="24" FontWeight="Bold"
|
||||
Foreground="{DynamicResource ForegroundColor}" Margin="0,0,0,20"/>
|
||||
|
||||
<!-- 基础颜色 -->
|
||||
<GroupBox Header="基础颜色" Margin="0,0,0,15">
|
||||
<StackPanel>
|
||||
<Border Background="{DynamicResource PrimaryColor}"
|
||||
Height="40" Margin="0,5">
|
||||
<TextBlock Text="PrimaryColor" Foreground="White"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</Border>
|
||||
<Border Background="{DynamicResource BackgroundColor}"
|
||||
BorderBrush="{DynamicResource BorderColor}" BorderThickness="1"
|
||||
Height="40" Margin="0,5">
|
||||
<TextBlock Text="BackgroundColor"
|
||||
Foreground="{DynamicResource ForegroundColor}"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 状态颜色 -->
|
||||
<GroupBox Header="状态颜色" Margin="0,0,0,15">
|
||||
<StackPanel>
|
||||
<Border Background="{DynamicResource SuccessColor}"
|
||||
Height="40" Margin="0,5">
|
||||
<TextBlock Text="✓ Success" Foreground="White"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</Border>
|
||||
<Border Background="{DynamicResource WarningColor}"
|
||||
Height="40" Margin="0,5">
|
||||
<TextBlock Text="⚠ Warning" Foreground="White"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</Border>
|
||||
<Border Background="{DynamicResource ErrorColor}"
|
||||
Height="40" Margin="0,5">
|
||||
<TextBlock Text="✗ Error" Foreground="White"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</Border>
|
||||
<Border Background="{DynamicResource InfoColor}"
|
||||
Height="40" Margin="0,5">
|
||||
<TextBlock Text="ℹ Info" Foreground="White"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 控件预览 -->
|
||||
<GroupBox Header="控件预览" Margin="0,0,0,15">
|
||||
<StackPanel>
|
||||
<!-- 按钮 -->
|
||||
<Button Content="普通按钮" Margin="0,5" Padding="10,5"
|
||||
Background="{DynamicResource ButtonBackgroundColor}"
|
||||
Foreground="{DynamicResource ForegroundColor}"/>
|
||||
|
||||
<!-- 输入框 -->
|
||||
<TextBox Text="输入框示例" Margin="0,5" Padding="5"
|
||||
Background="{DynamicResource InputBackgroundColor}"
|
||||
BorderBrush="{DynamicResource InputBorderColor}"/>
|
||||
|
||||
<!-- 复选框 -->
|
||||
<CheckBox Content="复选框示例" Margin="0,5"
|
||||
Foreground="{DynamicResource ForegroundColor}"/>
|
||||
|
||||
<!-- 单选按钮 -->
|
||||
<RadioButton Content="单选按钮示例" Margin="0,5"
|
||||
Foreground="{DynamicResource ForegroundColor}"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 文本示例 -->
|
||||
<GroupBox Header="文本示例">
|
||||
<StackPanel>
|
||||
<TextBlock Text="这是标题文本" FontSize="20" FontWeight="Bold"
|
||||
Foreground="{DynamicResource ForegroundColor}" Margin="0,5"/>
|
||||
<TextBlock Text="这是正文文本。主题切换后,所有使用 DynamicResource 的颜色都会自动更新,无需重启应用。"
|
||||
TextWrapping="Wrap" Foreground="{DynamicResource ForegroundColor}"
|
||||
Margin="0,5"/>
|
||||
<TextBlock Text="这是次要文本" FontSize="12" FontStyle="Italic"
|
||||
Foreground="Gray" Margin="0,5"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Window>
|
||||
```
|
||||
|
||||
### 4. 自定义主题颜色
|
||||
|
||||
```csharp
|
||||
public class CustomThemeViewModel : ViewModelBase
|
||||
{
|
||||
private readonly IThemeService _themeService;
|
||||
|
||||
public ICommand ChangePrimaryColorCommand { get; }
|
||||
|
||||
public CustomThemeViewModel(IThemeService themeService)
|
||||
{
|
||||
_themeService = themeService;
|
||||
|
||||
ChangePrimaryColorCommand = new RelayCommand(() =>
|
||||
{
|
||||
// 打开颜色选择器(可以使用第三方库或自定义)
|
||||
var color = Colors.DeepSkyBlue; // 示例:选择的颜色
|
||||
|
||||
// 更新主题颜色
|
||||
_themeService.SetColor("PrimaryColor", color);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 主题资源字典(可选 - 高级用法)
|
||||
|
||||
可以创建独立的资源字典文件:
|
||||
|
||||
**Themes/LightTheme.xaml**:
|
||||
```xml
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<SolidColorBrush x:Key="PrimaryColor" Color="#0078D7"/>
|
||||
<SolidColorBrush x:Key="BackgroundColor" Color="White"/>
|
||||
<SolidColorBrush x:Key="ForegroundColor" Color="Black"/>
|
||||
<!-- ... 其他颜色 -->
|
||||
</ResourceDictionary>
|
||||
```
|
||||
|
||||
**Themes/DarkTheme.xaml**:
|
||||
```xml
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<SolidColorBrush x:Key="PrimaryColor" Color="#0078D7"/>
|
||||
<SolidColorBrush x:Key="BackgroundColor" Color="#202020"/>
|
||||
<SolidColorBrush x:Key="ForegroundColor" Color="White"/>
|
||||
<!-- ... 其他颜色 -->
|
||||
</ResourceDictionary>
|
||||
```
|
||||
|
||||
## 🎓 练习建议
|
||||
|
||||
### 练习1:添加更多预设主题
|
||||
添加"高对比度"主题,适合视力不佳的用户。
|
||||
|
||||
### 练习2:主题动画过渡
|
||||
在切换主题时添加颜色渐变动画,而非瞬间切换。
|
||||
|
||||
### 练习3:保存主题偏好
|
||||
将用户选择的主题保存到配置文件,下次启动时自动应用。
|
||||
|
||||
### 练习4:自定义主题编辑器
|
||||
创建一个界面,允许用户自定义每种颜色,并导出/导入主题配置。
|
||||
|
||||
## 💡 常见问题
|
||||
|
||||
**Q: StaticResource 和 DynamicResource 的区别?**
|
||||
A:
|
||||
- `StaticResource`: 编译时绑定,主题切换后不会更新
|
||||
- `DynamicResource`: 运行时绑定,主题切换后自动更新(推荐用于主题)
|
||||
|
||||
**Q: 主题切换后部分控件没变化?**
|
||||
A: 确保使用了 `{DynamicResource}` 而非 `{StaticResource}`。
|
||||
|
||||
**Q: 如何跟随 Windows 系统主题?**
|
||||
A: 使用 `Theme.System`,Sharp.Wpf 会自动检测系统主题设置。
|
||||
|
||||
**Q: 能否为不同的窗口设置不同主题?**
|
||||
A: 可以,但不推荐。可以为每个 Window 设置独立的 ResourceDictionary。
|
||||
|
||||
## 📚 延伸阅读
|
||||
|
||||
- [WPF 资源](https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/systems/xaml-resources-overview)
|
||||
- [WPF 样式和模板](https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/controls/styles-templates-overview)
|
||||
- [Windows 主题检测](https://learn.microsoft.com/zh-cn/windows/apps/desktop/modernize/apply-windows-themes)
|
||||
- 综合示例:[11-FullStackDemo](../11-FullStackDemo/README.md)
|
||||
|
||||
---
|
||||
|
||||
**打造美观现代的用户界面!** 🎨
|
||||
Reference in new issue
Block a user