简体   繁体   English

如何处理 WinUI3 中的本地主题更改?

[英]How do I handle local theme changes in WinUI3?

I have an app that has a button to take a screenshot of a UserControl .我有一个应用程序,它有一个按钮可以截取UserControl的屏幕截图。 I'd like the screenshot to appear as as if Application.Current.RequestedTheme = ElementTheme.Light , even when Application.Current.RequestedTheme == ElementTheme.Dark .我希望屏幕截图看起来像Application.Current.RequestedTheme = ElementTheme.Light ,即使Application.Current.RequestedTheme == ElementTheme.Dark也是如此。

To do this, I am changing the requested theme of the UserControl, like this example:为此,我正在更改 UserControl 的请求主题,如下例所示:

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>
        <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# 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;
        }
    }
}

Clicking the button successfully changes TextBlock controls from white to black as appropriate on the screenshots, but the border colour does not change.单击该按钮成功地将TextBlock控件从屏幕截图上的白色适当更改为黑色,但边框颜色不会更改。

If I set the border colour like this:如果我这样设置边框颜色:

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

It works, however this is not an option for the actual user control as the content is generated dynamically.它可以工作,但是这不是实际用户控件的选项,因为内容是动态生成的。

How do I do the equivalent of setting the colour to {ThemeResource BorderBrush} in codebehind?如何在代码隐藏中将颜色设置为{ThemeResource BorderBrush}

I tried using a ThemeListener control, but it only seems to respond to theme changes at the app level.我尝试使用ThemeListener控件,但它似乎只响应应用程序级别的主题更改。

You need to use ThemeDicionaries for your custom colors.您需要为自定义 colors 使用ThemeDicionaries

<Application
    x:Class="How_do_I_handle_local_theme_changes_in_WinUI3.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
                <!--  Other merged dictionaries here  -->
            </ResourceDictionary.MergedDictionaries>
            <!--  Other app resources here  -->
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary x:Key="Default">
                    <SolidColorBrush
                        x:Key="CustomTextBlockForegroundThemeBrush"
                        Color="Red" />
                </ResourceDictionary>
                <ResourceDictionary x:Key="Light">
                    <SolidColorBrush
                        x:Key="CustomTextBlockForegroundThemeBrush"
                        Color="Green" />
                </ResourceDictionary>
                <ResourceDictionary x:Key="Dark">
                    <SolidColorBrush
                        x:Key="CustomTextBlockForegroundThemeBrush"
                        Color="Blue" />
                </ResourceDictionary>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

There is no backing class representation for the ThemeResource markup extension that the XAML processor uses but you should be able to get a reference to the theme dictionary and get the resource from there: XAML 处理器使用的ThemeResource标记扩展没有支持 class 表示,但您应该能够获取对主题字典的引用并从那里获取资源:

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;
}

My solution to this was to implement a static style in XAMl that was assigned in C#:我对此的解决方案是在 XAMl 中实现 static 样式,该样式在 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# 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;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM