.Net Maui/Xamarin 中的动态样式

use*_*414 4 xamarin xamarin.forms maui

假设我想显示日历。每一天 ( DayViewModel) 都可以具有影响样式的属性:

  • 是当前月份的某一天
  • 是周末
  • 有空吗

基于此,我想设计DayContentView如下样式:

  • 如果当前月份的某一天 -> 不透明度 1
  • 如果不是当前月份 -> 不透明度 0.5
  • 如果周末 -> 背景颜色是红色
  • 如果可用 -> 背景颜色为绿色

此外,最后一个属性(“是否可用”)可以根据用户的操作(单击“检查可用性”按钮)进行更改。

在其他框架中,我会创建一些样式/样式类,并根据这些标志相应地分配它们。但由于StyleClass不可绑定,我不能。我可以吗?也许有一些解决方法。

另一种选择可能是为所有组合创建单独的样式(如果需要,使用继承)。但首先,组合的数量增加了 2^n ,第二个问题是我不知道如何动态更改整个样式以更改其名称的视图。是否可以?

完成我很长的问题:如何正确/以聪明的方式做这件事?我不想在视图模型中存储颜色、字体大小、不透明度等值并手动绑定所有值。

Mic*_*viš 10

使用 s 也可以实现同样的效果DataTrigger

结果:

结果

主页.xaml

<Window
    x:Class="WpfApp6.MainWindow"
    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:local="clr-namespace:WpfApp6"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">

    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>

    <ItemsControl Margin="5" ItemsSource="{Binding Days}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type local:DayModel}">
                <Border
                    Padding="10"
                    Width="200"
                    Height="100"
                    Margin="5">
                    <Border.Style>
                        <Style TargetType="Border">
                            <Setter Property="Background" Value="Gray" />
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding IsDayOfCurrentMonth}" Value="False">
                                    <Setter Property="Opacity" Value="0.5" />
                                </DataTrigger>
                                <DataTrigger Binding="{Binding IsAvailable}" Value="True">
                                    <Setter Property="Background" Value="Green" />
                                </DataTrigger>
                                <DataTrigger Binding="{Binding IsWeekend}" Value="True">
                                    <Setter Property="Background" Value="Red" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Border.Style>
                    <StackPanel>
                        <TextBlock Text="{Binding IsDayOfCurrentMonth, StringFormat='IsDayOfCurrentMonth: {0}'}" />
                        <TextBlock Text="{Binding IsAvailable, StringFormat='IsAvailable: {0}'}" />
                        <TextBlock Text="{Binding IsWeekend, StringFormat='IsWeekend: {0}'}" />
                    </StackPanel>
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Window>
Run Code Online (Sandbox Code Playgroud)

DayModel.cs

public record DayModel(bool IsDayOfCurrentMonth, bool IsWeekend, bool IsAvailable);
Run Code Online (Sandbox Code Playgroud)

MainViewModel.cs

public class MainViewModel
{
    public ObservableCollection<DayModel> Days { get; } = new();

    public MainViewModel()
    {
        //Create all possible cominations of days
        for (int i = 0; i < 2; i++)
        {
            for (int j = 0; j < 2; j++)
            {
                for (int k = 0; k < 2; k++)
                {
                    Days.Add(new DayModel(i == 0, j == 0, k == 0));
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:通过多个控件共享样式

以下是多个控件如何共享同一个Stylewith的方式(本例中为三个控件中的两个):TriggersTextBlock

<DataTemplate DataType="{x:Type local:DayModel}">
    <Border
        Width="200"
        Height="100"
        Margin="5"
        Padding="10"
        Background="#eee">
        <StackPanel>
            <StackPanel.Resources>
                <Style x:Key="ColoredTextBlock" TargetType="TextBlock">
                    <Setter Property="Foreground" Value="Gray" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsDayOfCurrentMonth}" Value="False">
                            <Setter Property="Opacity" Value="0.5" />
                        </DataTrigger>
                        <DataTrigger Binding="{Binding IsAvailable}" Value="True">
                            <Setter Property="Foreground" Value="Green" />
                        </DataTrigger>
                        <DataTrigger Binding="{Binding IsWeekend}" Value="True">
                            <Setter Property="Foreground" Value="Red" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </StackPanel.Resources>
            <TextBlock Style="{StaticResource ColoredTextBlock}" Text="{Binding IsDayOfCurrentMonth, StringFormat='IsDayOfCurrentMonth: {0}'}" />
            <TextBlock Style="{StaticResource ColoredTextBlock}" Text="{Binding IsAvailable, StringFormat='IsAvailable: {0}'}" />
            <TextBlock Text="{Binding IsWeekend, StringFormat='IsWeekend: {0}'}" />
        </StackPanel>
    </Border>
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)

结果如下: 分享风格示例结果