Как реализовать пользовательские изменения цвета на странице контента? Допустим, у меня есть
<Grid
x:Name = "TopOverlay"
AbsoluteLayout.LayoutBounds = "0,0,1,0.08"
AbsoluteLayout.LayoutFlags = "WidthProportional,HeightProportional"
BackgroundColor = "{DynamicResource Background}"
И этикетка
<Label
Padding = "7,0"
FontAutoScalingEnabled = "False"
FontSize = "{Binding Source = {RelativeSource AncestorType = {x:Type local:ModalReaderViewModel}}, Path=FontSize}"
LineBreakMode = "WordWrap"
Text = "{Binding .}"
TextColor = "{DynamicResource DarkerTextColor}"
Мне нужно изменить эти значения Background
и DarkerTextColor
по выбору пользователя. Будет 3 разных варианта, каждый из которых будет содержать разные цвета фона и метки.
Видел некоторые подходы с использованием привязки AppTheme
, но мне нужно больше пользовательских опций, возможно, в будущем появится 4-5 разных тем, так как я могу создать сортировку привязки темы «myOwn», скажем так?
да, в итоге я просто изменил ключевые значения, это оказалось самым простым решением
Изменения динамического пользовательского интерфейса MAUI
Вот мое решение,
Дополнительную информацию о переключении тем см. в разделе Тема приложения.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source = "Resources/Styles/Colors.xaml" />
<ResourceDictionary Source = "Resources/Styles/Styles.xaml" />
<ResourceDictionary Source = "Resources/DarkTheme.xaml" />
<ResourceDictionary Source = "Resources/LightTheme.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
public void OnThemeSelectionChanged(object sender ,EventArgs e) {
var picker = (Picker)sender;
string selectedTheme = (string)picker.SelectedItem;
((App)Application.Current).ChangeTheme(selectedTheme);
}
public void ChangeTheme(string theme) {
ResourceDictionary newTheme = null;
switch (theme) {
case "Light":
newTheme = new Test806final.Resources.LightTheme();
break;
case "Dark":
newTheme = new Test806final.Resources.DarkTheme();
break;
}
if (newTheme != null && Application.Current != null) {
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Resources.MergedDictionaries.Add(newTheme);
}
}
Если вы хотите определить свою собственную тему, рассмотрите возможность создания для нее модели представления, например, здесь я определяю классы UserTheme
и UserThemes
и представляю ее как синглтон посредством внедрения зависимостей. Тогда мой MainPage.xaml
сможет использовать и обновлять его:
// UserThemes.cs
using CommunityToolkit.Mvvm.ComponentModel;
namespace MauiUserThemes;
public partial class UserTheme : ObservableObject
{
[ObservableProperty]
Color _backgroundColor = Colors.White;
[ObservableProperty]
Color _textColor = Colors.Black;
}
public partial class UserThemes : ObservableObject
{
public Dictionary<string, UserTheme> Themes { get; } = new()
{
["Light"] = new UserTheme(),
["Dark"] = new UserTheme { BackgroundColor = Colors.Black, TextColor = Colors.White },
["Blue"] = new UserTheme { BackgroundColor = Colors.Blue, TextColor = Colors.Yellow },
["Red"] = new UserTheme { BackgroundColor = Colors.Red, TextColor = Colors.Yellow }
};
public List<string> Names => Themes.Keys.ToList();
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(Current))]
string _currentName = "Light";
public UserTheme Current => Themes[CurrentName];
}
// MauiProgram.cs
//...
builder.Services.AddSingleton<UserThemes>();
builder.Services.AddTransient<MainPage>();
//...
<!-- MainPage.xaml -->
<ContentPage
x:Class = "MauiUserThemes.MainPage"
xmlns = "http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml"
x:Name = "mainPage"
BackgroundColor = "{Binding Themes.Current.BackgroundColor, Source = {Reference mainPage}}">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType = "Label">
<Setter Property = "TextColor" Value = "{Binding Themes.Current.TextColor, Source = {Reference mainPage}}" />
<Setter Property = "Margin" Value = "0,5,0,5" />
</Style>
<Style TargetType = "Button">
<Setter Property = "BackgroundColor" Value = "{Binding Themes.Current.BackgroundColor, Source = {Reference mainPage}}" />
<Setter Property = "TextColor" Value = "{Binding Themes.Current.TextColor, Source = {Reference mainPage}}" />
<Setter Property = "BorderColor" Value = "{Binding Themes.Current.TextColor, Source = {Reference mainPage}}" />
<Setter Property = "BorderWidth" Value = "1" />
<Setter Property = "Margin" Value = "0,5,0,5" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<VerticalStackLayout Margin = "10,10,10,10">
<Label Text = "Select Theme:" />
<CollectionView Margin = "10,0,10,0" ItemsSource = "{Binding Themes.Names, Source = {Reference mainPage}}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Button Clicked = "Button_Clicked" Text = "{Binding}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Label Text = "{Binding Themes.CurrentName, Source = {Reference mainPage}, StringFormat='Selected Theme: {0}'}" />
</VerticalStackLayout>
</ContentPage>
// MainPage.xaml.cs
// MainPage.xaml.cs
namespace MauiUserThemes;
public partial class MainPage : ContentPage
{
public UserThemes Themes { get; }
public MainPage(UserThemes Themes)
{
this.Themes = Themes;
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
Button btn = (Button)sender;
Themes.CurrentName = btn.Text;
}
}
Пробовали ли вы обновить значения в коде программной части или ViewModel? Как пользователь выберет? Вы можете манипулировать значениями в коде программной части или использовать привязки, например. в ViewModel.