maui-theming

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

.NET MAUI Theming

.NET MAUI 主题设置

Two main approaches exist for theming MAUI apps: AppThemeBinding (automatic OS theme response) and ResourceDictionary theming (custom themes with runtime switching). They can be combined.
.NET MAUI应用的主题设置主要有两种方法:AppThemeBinding(自动响应系统主题)和ResourceDictionary主题设置(自定义主题并支持运行时切换)。这两种方法可以结合使用。

1. AppThemeBinding (OS Theme Response)

1. AppThemeBinding(响应系统主题)

AppThemeBinding
is a markup extension that selects a value based on the current system theme.
AppThemeBinding
是一种标记扩展,可根据当前系统主题选择对应的值。

Properties

属性

PropertyDescription
Light
Value used when the device is in light mode
Dark
Value used when the device is in dark mode
Default
Fallback value when the device theme is unknown
属性说明
Light
设备处于浅色模式时使用的值
Dark
设备处于深色模式时使用的值
Default
设备主题未知时的回退值

XAML Usage

XAML 使用示例

xml
<Label Text="Themed text"
       TextColor="{AppThemeBinding Light=Green, Dark=Red}"
       BackgroundColor="{AppThemeBinding Light=White, Dark=Black}" />

<!-- With StaticResource or DynamicResource values -->
<Label TextColor="{AppThemeBinding Light={StaticResource LightPrimary},
                                   Dark={StaticResource DarkPrimary}}" />
xml
<Label Text="主题化文本"
       TextColor="{AppThemeBinding Light=Green, Dark=Red}"
       BackgroundColor="{AppThemeBinding Light=White, Dark=Black}" />

<!-- 结合StaticResource或DynamicResource使用 -->
<Label TextColor="{AppThemeBinding Light={StaticResource LightPrimary},
                                   Dark={StaticResource DarkPrimary}}" />

C# Extension Methods

C# 扩展方法

csharp
var label = new Label();
// Color-specific helper
label.SetAppThemeColor(Label.TextColorProperty, Colors.Green, Colors.Red);

// Generic helper for any type
label.SetAppTheme<Color>(Label.TextColorProperty, Colors.Green, Colors.Red);
csharp
var label = new Label();
// 颜色专用辅助方法
label.SetAppThemeColor(Label.TextColorProperty, Colors.Green, Colors.Red);

// 适用于任意类型的通用辅助方法
label.SetAppTheme<Color>(Label.TextColorProperty, Colors.Green, Colors.Red);

2. ResourceDictionary Theming (Custom Themes)

2. ResourceDictionary主题设置(自定义主题)

Use separate
ResourceDictionary
files with matching keys to define themes, then swap them at runtime.
使用独立的
ResourceDictionary
文件,通过匹配的键定义主题,然后在运行时切换这些文件。

Define Theme Dictionaries

定义主题字典

Each ResourceDictionary must have a code-behind file that calls
InitializeComponent()
.
LightTheme.xaml
xml
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="MyApp.Themes.LightTheme">
    <Color x:Key="PageBackgroundColor">White</Color>
    <Color x:Key="PrimaryTextColor">#333333</Color>
    <Color x:Key="AccentColor">#2196F3</Color>
</ResourceDictionary>
LightTheme.xaml.cs
csharp
namespace MyApp.Themes;

public partial class LightTheme : ResourceDictionary
{
    public LightTheme() => InitializeComponent();
}
DarkTheme.xaml.cs — same pattern, different values, same keys.
每个ResourceDictionary必须包含代码后置文件,并调用
InitializeComponent()
LightTheme.xaml
xml
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="MyApp.Themes.LightTheme">
    <Color x:Key="PageBackgroundColor">White</Color>
    <Color x:Key="PrimaryTextColor">#333333</Color>
    <Color x:Key="AccentColor">#2196F3</Color>
</ResourceDictionary>
LightTheme.xaml.cs
csharp
namespace MyApp.Themes;

public partial class LightTheme : ResourceDictionary
{
    public LightTheme() => InitializeComponent();
}
DarkTheme.xaml.cs —— 遵循相同模式,仅修改值,保持键一致。

Consume with DynamicResource

结合DynamicResource使用

Use
DynamicResource
(not
StaticResource
) so values update at runtime when the dictionary changes:
xml
<ContentPage BackgroundColor="{DynamicResource PageBackgroundColor}">
    <Label Text="Hello"
           TextColor="{DynamicResource PrimaryTextColor}" />
    <Button Text="Action"
            BackgroundColor="{DynamicResource AccentColor}" />
</ContentPage>
使用
DynamicResource
(而非
StaticResource
),这样当字典变化时,值会在运行时自动更新:
xml
<ContentPage BackgroundColor="{DynamicResource PageBackgroundColor}">
    <Label Text="你好"
           TextColor="{DynamicResource PrimaryTextColor}" />
    <Button Text="操作"
            BackgroundColor="{DynamicResource AccentColor}" />
</ContentPage>

Switch Themes at Runtime

运行时切换主题

csharp
void ApplyTheme(ResourceDictionary theme)
{
    var mergedDictionaries = Application.Current!.Resources.MergedDictionaries;
    mergedDictionaries.Clear();
    mergedDictionaries.Add(theme);
}

// Usage
ApplyTheme(new LightTheme());
ApplyTheme(new DarkTheme());
csharp
void ApplyTheme(ResourceDictionary theme)
{
    var mergedDictionaries = Application.Current!.Resources.MergedDictionaries;
    mergedDictionaries.Clear();
    mergedDictionaries.Add(theme);
}

// 使用示例
ApplyTheme(new LightTheme());
ApplyTheme(new DarkTheme());

System Theme Detection

系统主题检测

Current Theme

获取当前主题

csharp
AppTheme currentTheme = Application.Current!.RequestedTheme;
// Returns AppTheme.Light, AppTheme.Dark, or AppTheme.Unspecified
csharp
AppTheme currentTheme = Application.Current!.RequestedTheme;
// 返回值为AppTheme.Light、AppTheme.Dark或AppTheme.Unspecified

Override the System Theme

覆盖系统主题

csharp
// Force a specific theme regardless of OS setting
Application.Current!.UserAppTheme = AppTheme.Dark;

// Reset to follow the system theme
Application.Current!.UserAppTheme = AppTheme.Unspecified;
csharp
// 强制使用特定主题,不受系统设置影响
Application.Current!.UserAppTheme = AppTheme.Dark;

// 重置为跟随系统主题
Application.Current!.UserAppTheme = AppTheme.Unspecified;

React to Theme Changes

响应主题变化

csharp
Application.Current!.RequestedThemeChanged += (s, e) =>
{
    AppTheme newTheme = e.RequestedTheme;
    // Update UI or switch ResourceDictionaries
};
csharp
Application.Current!.RequestedThemeChanged += (s, e) =>
{
    AppTheme newTheme = e.RequestedTheme;
    // 更新UI或切换ResourceDictionaries
};

Combining Both Approaches

两种方法结合使用

Use
AppThemeBinding
with
DynamicResource
values for maximum flexibility:
xml
<Label TextColor="{AppThemeBinding
    Light={DynamicResource LightPrimary},
    Dark={DynamicResource DarkPrimary}}" />
Or react to system changes and swap full ResourceDictionaries:
csharp
Application.Current!.RequestedThemeChanged += (s, e) =>
{
    ApplyTheme(e.RequestedTheme == AppTheme.Dark
        ? new DarkTheme()
        : new LightTheme());
};
AppThemeBinding
DynamicResource
值结合,实现最大灵活性:
xml
<Label TextColor="{AppThemeBinding
    Light={DynamicResource LightPrimary},
    Dark={DynamicResource DarkPrimary}}" />
或者监听系统主题变化,切换完整的ResourceDictionary:
csharp
Application.Current!.RequestedThemeChanged += (s, e) =>
{
    ApplyTheme(e.RequestedTheme == AppTheme.Dark
        ? new DarkTheme()
        : new LightTheme());
};

Platform Support & Gotchas

平台支持与注意事项

PlatformMinimum Version
iOS13+
Android10+ (API 29)
macOS Catalyst10.14+
Windows10+
平台最低版本
iOS13+
Android10+ (API 29)
macOS Catalyst10.14+
Windows10+

Android: ConfigChanges.UiMode

Android:ConfigChanges.UiMode

MainActivity
must include
ConfigChanges.UiMode
or theme change events will not fire and the activity may restart instead:
csharp
[Activity(Theme = "@style/Maui.SplashTheme",
          MainLauncher = true,
          ConfigurationChanges = ConfigChanges.ScreenSize
                               | ConfigChanges.Orientation
                               | ConfigChanges.UiMode  // Required for theme detection
                               | ConfigChanges.ScreenLayout
                               | ConfigChanges.SmallestScreenSize
                               | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity { }
MainActivity
必须包含
ConfigChanges.UiMode
,否则主题变化事件不会触发,且活动可能会重启:
csharp
[Activity(Theme = "@style/Maui.SplashTheme",
          MainLauncher = true,
          ConfigurationChanges = ConfigChanges.ScreenSize
                               | ConfigChanges.Orientation
                               | ConfigChanges.UiMode  // 主题检测必需
                               | ConfigChanges.ScreenLayout
                               | ConfigChanges.SmallestScreenSize
                               | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity { }

CSS Theming Limitation

CSS主题设置限制

MAUI supports CSS styling, but CSS-based themes cannot be swapped dynamically at runtime. Use ResourceDictionary theming instead for dynamic theme switching.
MAUI支持CSS样式,但基于CSS的主题无法在运行时动态切换。如果需要动态主题切换,请使用ResourceDictionary主题设置方法。

Quick Reference

快速参考

  • OS light/dark
    AppThemeBinding
    markup extension
  • Theme colors in C#
    SetAppThemeColor()
    ,
    SetAppTheme<T>()
  • Read OS theme
    Application.Current.RequestedTheme
  • Force theme
    Application.Current.UserAppTheme = AppTheme.Dark
  • Theme changes
    RequestedThemeChanged
    event
  • Custom switching → Swap
    ResourceDictionary
    in
    MergedDictionaries
  • Runtime bindings
    DynamicResource
    (not
    StaticResource
    )
  • 系统明暗模式适配
    AppThemeBinding
    标记扩展
  • C#中设置主题颜色
    SetAppThemeColor()
    SetAppTheme<T>()
  • 读取系统主题
    Application.Current.RequestedTheme
  • 强制设置主题
    Application.Current.UserAppTheme = AppTheme.Dark
  • 监听主题变化
    RequestedThemeChanged
    事件
  • 自定义主题切换 → 在
    MergedDictionaries
    中替换
    ResourceDictionary
  • 运行时绑定
    DynamicResource
    (而非
    StaticResource