page - xaml style resources




Установка или изменение темыResource в коде (2)

Мои вопросы очень специфичны для ThemeResources в приложении для Windows 10 Store. К сожалению, некоторые вещи, доступные в «классическом» WPF, различны или недоступны здесь.

То, что я пытаюсь достичь для множества элементов ui:

  • Позвольте пользователю использовать цвет акцента системы (в XAML это будет {ThemeResource SystemAccentColor} как значение.)
  • Разрешите пользователю использовать пользовательский / фиксированный цвет. (Я могу переопределить ключ SystemAccentColor в resourcedictionary)
  • Позволяет переключаться между системным акцентом и пользовательским цветом во время выполнения (я мог бы привязываться к цвету вместо использования ресурса)

Но я не нашел хорошего решения для достижения всего этого. Если у меня есть собственный словарь ресурсов с пользовательским цветом, я не избавлюсь от него, когда пользователь захочет вернуться к цвету акцента системы. И использование свойства, которое я связываю, имеет недостаток, который я не понимаю, если пользователь меняет цвет акцента в системных настройках во время работы приложения - используя разметку {ThemeResource} .

Любые идеи, как это сделать правильно? Если бы было возможно установить ThemeResource из кода, я мог бы написать какое-то поведение для этого, но, похоже, оно не будет доступно.


В Windows 10 имя «Цвет акцента» изменяется на «SystemControlHighlightAccentBrush», и это ThemeResource

Пример использования

<TextBlock Foreground="{ThemeResource SystemControlHighlightAccentBrush}"
                   Text="This is a sample text" />

Чтобы переопределить его, просто измените его значение в App.xaml

<Application.Resources>
    <SolidColorBrush x:Key="SystemControlHighlightAccentBrush" Color="Orange" />
</Application.Resources>

Чтобы переключиться, это немного сложнее. Сначала вам нужно установить весь цвет для каждой темы в App.xaml

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.ThemeDictionaries>
            <ResourceDictionary x:Key="Default">
                <SolidColorBrush x:Key="SystemControlHighlightAccentBrush" Color="Orange" />
            </ResourceDictionary>
            <ResourceDictionary x:Key="Dark">
                <SolidColorBrush x:Key="SystemControlHighlightAccentBrush" Color="Green" />
            </ResourceDictionary>
            <ResourceDictionary x:Key="Light">
                <SolidColorBrush x:Key="SystemControlHighlightAccentBrush" Color="Blue" />
            </ResourceDictionary>
        </ResourceDictionary.ThemeDictionaries>
    </ResourceDictionary>
</Application.Resources>

Затем, на странице или в коде позади, вы устанавливаете соответствующую тему

<TextBlock x:Name="TestTextBlock"
               Foreground="{ThemeResource SystemControlHighlightAccentBrush}"
               RequestedTheme="Dark"
               Text="This is a sample text" />

или в C #

TestTextBlock.RequestedTheme = ElementTheme.Dark;

Однажды я столкнулся с той же проблемой, и я также не нашел способ программно изменить ThemeResource, чтобы он изменился вместе с темой телефона. Тем не менее, есть способ достичь того, чего вы хотите, но это громоздко и может потребоваться много работы, если вы хотите реализовать это для многих элементов управления.

Основная идея заключается в использовании VisualStates для изменения с / на ThemeResource - состояния определены в xaml, поэтому это будет работать с ThemeResources . Затем в коде вы можете вызвать изменение на значение темы телефона. Ниже приведена кнопка выбора образца на цвет темы / пользователя.

<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button Name="ColorBtn" Content="Change users color to green rom red"/>
    <local:ExtendedButton x:Name="UserBtn" Content="Change to user's theme" UserBackground="Red">
        <local:ExtendedButton.Style>
            <Style TargetType="local:ExtendedButton">
                <!--default style's setters-->
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="local:ExtendedButton">
                            <Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
                                <VisualStateManager.VisualStateGroups>
                                    <VisualStateGroup>
                                        <VisualState x:Name="ThemeColor">
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="RootGrid">
                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemColorControlAccentColor}"/>
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="UserColor"/>
                                    </VisualStateGroup>
                                    <!--rest of default visual states-->
                                </VisualStateManager.VisualStateGroups>
                                <ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </local:ExtendedButton.Style>
    </local:ExtendedButton>
</StackPanel>

и код позади:

public class ExtendedButton : Button
{
    public SolidColorBrush UserBackground
    {
        get { return (SolidColorBrush)GetValue(UserBackgroundProperty); }
        set { SetValue(UserBackgroundProperty, value); }
    }

    public static readonly DependencyProperty UserBackgroundProperty =
        DependencyProperty.Register("UserBackground", typeof(SolidColorBrush), typeof(ExtendedButton),
            new PropertyMetadata(new SolidColorBrush(Colors.Red), (s, e) =>
            { if ((s as ExtendedButton).IsUserTheme) (s as ExtendedButton).Background = e.NewValue as SolidColorBrush; }));

    // we need some property to indicate if to use user's theme or phone's
    public bool IsUserTheme
    {
        get { return (bool)GetValue(IsUserThemeProperty); }
        set { SetValue(IsUserThemeProperty, value); }
    }

    public static readonly DependencyProperty IsUserThemeProperty =
        DependencyProperty.Register("IsUserTheme", typeof(bool), typeof(ExtendedButton), new PropertyMetadata(false, (s, e) =>
        {
            if ((bool)e.NewValue)
            {
                VisualStateManager.GoToState((s as ExtendedButton), "UserColor", false);
                (s as ExtendedButton).Background = (s as ExtendedButton).UserBackground;                
            }
            else VisualStateManager.GoToState((s as ExtendedButton), "ThemeColor", false);
        }));
}

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        Random random = new Random();
        UserBtn.Click += (s, e) => UserBtn.IsUserTheme = !UserBtn.IsUserTheme; ;
        ColorBtn.Click += (s, e) => UserBtn.UserBackground = new SolidColorBrush(Color.FromArgb(0xFF, (byte)random.Next(255), (byte)random.Next(255), (byte)random.Next(255)));
    }
}

Это намного выше, чем просто изменить один цвет, но он должен работать и, возможно, даст вам представление. Это также DependencyProperties, поэтому вы можете использовать привязку, если это необходимо.





uwp