You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI 3自定义按钮主题咨询:适配明暗主题与多样式区分

WinUI 3 自定义主题按钮实现方案

你不需要创建全新的自定义Button控件,通过主题资源配置+修改控件模板,再配合轻量的附加属性,就能实现你要的效果,同时支持明暗主题自动切换。以下是具体步骤:

1. 定义明暗主题对应的颜色资源

在App.xaml或单独的资源字典文件中,为Primary、Secondary按钮的各个状态(正常、悬停、点击等)定义不同主题下的颜色:

<ResourceDictionary>
    <ResourceDictionary.ThemeDictionaries>
        <!-- 浅色主题 -->
        <ResourceDictionary x:Key="Light">
            <!-- Primary按钮颜色 -->
            <SolidColorBrush x:Key="PrimaryButtonBackground" Color="#0078D4"/>
            <SolidColorBrush x:Key="PrimaryButtonForeground" Color="White"/>
            <SolidColorBrush x:Key="PrimaryButtonHoverBackground" Color="#106EBE"/>
            <SolidColorBrush x:Key="PrimaryButtonPressedBackground" Color="#005A9E"/>
            <SolidColorBrush x:Key="PrimaryButtonBorderBrush" Color="#0078D4"/>

            <!-- Secondary按钮颜色 -->
            <SolidColorBrush x:Key="SecondaryButtonBackground" Color="#EDEDED"/>
            <SolidColorBrush x:Key="SecondaryButtonForeground" Color="#1F1F1F"/>
            <SolidColorBrush x:Key="SecondaryButtonHoverBackground" Color="#DCDCDC"/>
            <SolidColorBrush x:Key="SecondaryButtonPressedBackground" Color="#C5C5C5"/>
            <SolidColorBrush x:Key="SecondaryButtonBorderBrush" Color="#EDEDED"/>
        </ResourceDictionary>

        <!-- 深色主题 -->
        <ResourceDictionary x:Key="Dark">
            <!-- Primary按钮颜色 -->
            <SolidColorBrush x:Key="PrimaryButtonBackground" Color="#0078D4"/>
            <SolidColorBrush x:Key="PrimaryButtonForeground" Color="White"/>
            <SolidColorBrush x:Key="PrimaryButtonHoverBackground" Color="#106EBE"/>
            <SolidColorBrush x:Key="PrimaryButtonPressedBackground" Color="#005A9E"/>
            <SolidColorBrush x:Key="PrimaryButtonBorderBrush" Color="#0078D4"/>

            <!-- Secondary按钮颜色 -->
            <SolidColorBrush x:Key="SecondaryButtonBackground" Color="#323232"/>
            <SolidColorBrush x:Key="SecondaryButtonForeground" Color="#EDEDED"/>
            <SolidColorBrush x:Key="SecondaryButtonHoverBackground" Color="#404040"/>
            <SolidColorBrush x:Key="SecondaryButtonPressedBackground" Color="#4A4A4A"/>
            <SolidColorBrush x:Key="SecondaryButtonBorderBrush" Color="#323232"/>
        </ResourceDictionary>
    </ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>

2. 自定义Button样式(控件模板)

复制WinUI 3默认的Button模板,替换其中的颜色引用为上面定义的主题资源,分别创建Primary和Secondary按钮的样式:

Primary按钮样式

<Style x:Key="PrimaryButtonStyle" TargetType="Button">
    <Setter Property="Background" Value="{ThemeResource PrimaryButtonBackground}"/>
    <Setter Property="Foreground" Value="{ThemeResource PrimaryButtonForeground}"/>
    <Setter Property="BorderBrush" Value="{ThemeResource PrimaryButtonBorderBrush}"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Padding" Value="8,4"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="PointerOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PrimaryButtonHoverBackground}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PrimaryButtonPressedBackground}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <!-- 可补充Disabled等其他状态的样式 -->
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <ContentPresenter x:Name="ContentPresenter"
                                      Content="{TemplateBinding Content}"
                                      ContentTemplate="{TemplateBinding ContentTemplate}"
                                      Foreground="{TemplateBinding Foreground}"
                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                      Padding="{TemplateBinding Padding}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Secondary按钮样式

类似Primary样式,只需将所有资源引用替换为Secondary对应的键即可。

3. 关联type属性与样式

原生Button没有type属性,我们可以通过附加属性实现这个语法:

编写附加属性代码

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace YourAppNamespace
{
    public static class ButtonExtensions
    {
        public static readonly DependencyProperty TypeProperty =
            DependencyProperty.RegisterAttached(
                "Type",
                typeof(string),
                typeof(ButtonExtensions),
                new PropertyMetadata(null, OnTypeChanged));

        public static string GetType(Button button)
        {
            return (string)button.GetValue(TypeProperty);
        }

        public static void SetType(Button button, string value)
        {
            button.SetValue(TypeProperty, value);
        }

        private static void OnTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is Button button)
            {
                button.Style = e.NewValue switch
                {
                    "Primary" => (Style)button.Resources["PrimaryButtonStyle"],
                    "Secondary" => (Style)button.Resources["SecondaryButtonStyle"],
                    _ => null // 恢复默认样式
                };
            }
        }
    }
}

在XAML中使用

添加命名空间引用后,即可用type语法设置按钮:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:YourAppNamespace">

    <StackPanel>
        <Button local:ButtonExtensions.Type="Primary">Action1</Button>
        <Button local:ButtonExtensions.Type="Secondary">Action2</Button>
    </StackPanel>
</Page>

核心原理说明

  • 用ThemeResource引用颜色资源,系统会自动根据当前应用的明暗主题切换对应的颜色值;
  • 自定义样式基于原生Button模板修改,保留了Button的所有原生行为,无需从零创建控件;
  • 附加属性实现了type语法的快捷设置,避免了每次手动指定Style的繁琐。

内容的提问来源于stack exchange,提问作者holycreeper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 02:25:00