У меня есть приложение, в котором есть кнопка, чтобы сделать скриншот 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>
С#
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, но, похоже, он реагирует только на изменения темы на уровне приложения.





Использование 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>
ОБНОВИТЬ
Если вам нужно сделать это программно:
private void UpdateBrush()
{
foreach (ResourceDictionary themeDictionary in Application.Current.Resources.MergedDictionaries.Select(x => x.ThemeDictionaries))
{
ResourceDictionary? targetDictionary = null;
if (themeDictionary.TryGetValue(RequestedTheme.ToString(), out var requestedThemeDictionary) is true)
{
targetDictionary = requestedThemeDictionary as ResourceDictionary;
}
else if (themeDictionary.TryGetValue(ElementTheme.Default.ToString(), out var defaultThemeDictionary) is true)
{
targetDictionary = defaultThemeDictionary as ResourceDictionary;
}
if (targetDictionary?.TryGetValue("TextFillColorPrimary", out object resource) is true &&
resource is Color color)
{
Border.BorderBrush = new SolidColorBrush(color);
}
}
}
Обновил мой ответ. Я подтвердил, что это работает.
Он работает, но требует XAML, мой вопрос задавал эквивалент С#.
Сожалею. Обновил мой ответ.
Для расширения разметки ThemeResource, которое использует процессор XAML, нет представления поддерживающего класса, но вы должны иметь возможность получить ссылку на словарь темы и получить оттуда ресурс:
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;
}
Спасибо, мм8, к сожалению, я не смог найти способ обнаружить запрошенное изменение темы, но эта реализация возвращает правильный цвет при ручном запуске.
Мое решение состояло в том, чтобы реализовать статический стиль в XAMl, который был назначен в C#:
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>
С#
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;
}
}
}
Привет, Эндрю, я отредактировал свой вопрос, чтобы (надеюсь) прояснить проблему.