【问题标题】:How do I handle local theme changes in WinUI3?如何处理 WinUI3 中的本地主题更改?
【发布时间】:2022-09-30 16:01:26
【问题描述】:

我有一个应用程序,它有一个按钮可以截取UserControl 的屏幕截图。我希望屏幕截图看起来像Application.Current.RequestedTheme = ElementTheme.Light,即使Application.Current.RequestedTheme == ElementTheme.Dark

为此,我正在更改 UserControl 的请求主题,如下例所示:

XAML

<UserControl
    x:Class=\"TestWinUI3App.UserControl1\"
    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"
    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"
    xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"
    xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"
    mc:Ignorable=\"d\">

    <UserControl.Resources>
        <ResourceDictionary>            
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary x:Key=\"Default\">
                    <StaticResource x:Key=\"BorderBrush\" ResourceKey=\"TextFillColorPrimaryBrush\"/>
                </ResourceDictionary>
                <ResourceDictionary x:Key=\"Light\">
                    <StaticResource x:Key=\"BorderBrush\" ResourceKey=\"TextFillColorPrimaryBrush\"/> 
                </ResourceDictionary>
                <ResourceDictionary x:Key=\"Dark\">
                    <StaticResource x:Key=\"BorderBrush\" ResourceKey=\"TextFillColorPrimaryBrush\"/>           
                </ResourceDictionary>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>

    <StackPanel Orientation=\"Vertical\">
        <Button Content=\"Switch theme\" Tapped=\"Button_Tapped\"/>
        <Border x:Name=\"Border\" BorderThickness=\"1\">
            <TextBlock Text=\"Theme text\"/>
        </Border>
    </StackPanel>
</UserControl>

C#

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;

namespace TestWinUI3App
{
    public sealed partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
            UpdateBrush();
        }

        private void Button_Tapped(object sender, TappedRoutedEventArgs e)
        {
            RequestedTheme = RequestedTheme == ElementTheme.Dark ? ElementTheme.Light : ElementTheme.Dark;
            UpdateBrush();
        }

        private void UpdateBrush()
        {
            Border.BorderBrush = Resources[\"BorderBrush1\"] as SolidColorBrush;
        }
    }
}

单击按钮成功将屏幕截图上的TextBlock 控件从白色更改为黑色,但边框颜色不会改变。

如果我这样设置边框颜色:

<Border x:Name=\"Border\" BorderThickness=\"1\" BorderBrush=\"{ThemeResource BorderBrush}\">

它可以工作,但是这不是实际用户控件的选项,因为内容是动态生成的。

如何在代码隐藏中将颜色设置为 {ThemeResource BorderBrush}

我尝试使用ThemeListener 控件,但它似乎只响应应用程序级别的主题更改。

    标签: c# winui-3


    【解决方案1】:

    XAML 处理器使用的 ThemeResource 标记扩展没有支持类表示,但您应该能够获取对主题字典的引用并从那里获取资源:

    private void Button_Tapped(object sender, TappedRoutedEventArgs e)
    {
        RequestedTheme = RequestedTheme == ElementTheme.Dark ? ElementTheme.Light : ElementTheme.Dark;
        UpdateBrush();
    }
    
    private void UpdateBrush()
    {
        var themeDictionary = Resources.ThemeDictionaries[ActualTheme.ToString()] as ResourceDictionary;
        Border.BorderBrush = themeDictionary["BorderBrush"] as SolidColorBrush;
    }
    

    【讨论】:

    • 谢谢mm8,不幸的是我找不到检测请求的主题更改的方法,但是这个实现在手动触发时确实返回了正确的颜色。
    【解决方案2】:

    使用TextFillColorPrimary 直接切换边框颜色。这样您就无需致电UpdateBrush()

    <UserControl
        x:Class="TestWinUI3App.UserControl1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:ThemeTest"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <!--<UserControl.Resources>
            <ResourceDictionary>
                <ResourceDictionary.ThemeDictionaries>
                    <ResourceDictionary x:Key="Default">
                        <StaticResource x:Key="BorderBrush" ResourceKey="TextFillColorPrimaryBrush"/>
                    </ResourceDictionary>
                    <ResourceDictionary x:Key="Light">
                        <StaticResource x:Key="BorderBrush" ResourceKey="TextFillColorPrimaryBrush"/>
                    </ResourceDictionary>
                    <ResourceDictionary x:Key="Dark">
                        <StaticResource x:Key="BorderBrush" ResourceKey="TextFillColorPrimaryBrush"/>
                    </ResourceDictionary>
                </ResourceDictionary.ThemeDictionaries>
            </ResourceDictionary>
        </UserControl.Resources>-->
    
        <StackPanel Orientation="Vertical">
            <Button Content="Switch theme" Tapped="Button_Tapped"/>
            <Border x:Name="Border" BorderThickness="1" BorderBrush="{ThemeResource TextFillColorPrimary}">
                <TextBlock Text="Theme text"/>
            </Border>
        </StackPanel>
    </UserControl>
    

    【讨论】:

    • 嗨,安德鲁,我编辑了我的问题以(希望)使问题更清楚
    • 更新了我的答案。我确认它有效。
    • 它可以工作,但需要 XAML,我的问题是要求 C# 等效项。
    【解决方案3】:

    我对此的解决方案是在 C# 中分配的 XAMl 中实现静态样式:

    XAML

    <UserControl
        x:Class="TestWinUI3App.UserControl1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <UserControl.Resources>
            <Style x:Key="BorderStyle" TargetType="Border">
                <Setter Property="BorderBrush" Value="{ThemeResource TextFillColorPrimary}"/>
            </Style>
        </UserControl.Resources>
    
        <StackPanel Orientation="Vertical">
            <Button Content="Switch theme" Tapped="Button_Tapped"/>
            <Border x:Name="Border" BorderThickness="1">
                <TextBlock Text="Theme text"/>
            </Border>
        </StackPanel>
    </UserControl>
    

    C#

    using Microsoft.UI.Xaml;
    using Microsoft.UI.Xaml.Controls;
    using Microsoft.UI.Xaml.Input;
    
    namespace TestWinUI3App
    {
        public sealed partial class UserControl1 : UserControl
        {
            public UserControl1()
            {
                InitializeComponent();
                Border.Style = Resources["BorderStyle"] as Style;
            }
    
            private void Button_Tapped(object sender, TappedRoutedEventArgs e)
            {
                RequestedTheme = RequestedTheme == ElementTheme.Dark ? ElementTheme.Light : ElementTheme.Dark;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-06-14
      • 2022-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-18
      • 2015-05-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多