FlipPanel2类是负责控制逻辑。
FlipPanel2.cs
using Avalonia; using Avalonia.Animation.Easings; using Avalonia.Controls; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using System; namespace AvaloniaUI { [TemplatePart("PART_FrontHost", typeof(Border))] [TemplatePart("PART_BackHost", typeof(Border))] [TemplatePart("PART_FlipButton", typeof(ToggleButton))] public class FlipPanel2 : TemplatedControl { // ========== 依赖属性 ========== public static readonly StyledProperty<Control?> FrontContentProperty = AvaloniaProperty.Register<FlipPanel2, Control?>(nameof(FrontContent)); public static readonly StyledProperty<Control?> BackContentProperty = AvaloniaProperty.Register<FlipPanel2, Control?>(nameof(BackContent)); public static readonly StyledProperty<bool> IsFlippedProperty = AvaloniaProperty.Register<FlipPanel2, bool>(nameof(IsFlipped)); public static readonly StyledProperty<double> FlipAngleProperty = AvaloniaProperty.Register<FlipPanel2, double>(nameof(FlipAngle), 0d); // ========== CLR 包装 ========== public Control? FrontContent { get => GetValue(FrontContentProperty); set => SetValue(FrontContentProperty, value); } public Control? BackContent { get => GetValue(BackContentProperty); set => SetValue(BackContentProperty, value); } public bool IsFlipped { get => GetValue(IsFlippedProperty); set => SetValue(IsFlippedProperty, value); } public double FlipAngle { get => GetValue(FlipAngleProperty); set => SetValue(FlipAngleProperty, value); } // ========== 模板部件 ========== private ToggleButton? flipButton; public FlipPanel2() { // 监听属性变化 this.GetObservable(IsFlippedProperty).Subscribe(_ => { UpdatePseudoClasses(); }); } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); flipButton = e.NameScope.Find<ToggleButton>("PART_FlipButton"); if (flipButton != null) flipButton.Click += (_, _) => ToggleFlipped(); UpdatePseudoClasses(); } private void ToggleFlipped() { IsFlipped = !IsFlipped; } private void UpdatePseudoClasses() { PseudoClasses.Set(":flipped", IsFlipped); } } }
测试的Style.axaml
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:AvaloniaUI"> <Design.PreviewWith> </Design.PreviewWith> <Style Selector="local|FlipPanel2"> <!-- 默认角度 --> <Setter Property="local:FlipPanel2.FlipAngle" Value="0"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Grid RowDefinitions="*, auto"> <!-- Front content --> <Border x:Name="PART_FrontHost" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding CornerRadius}" Background="#E0F7FA" Opacity="1"> <ContentPresenter Content="{TemplateBinding FrontContent}" HorizontalAlignment="Center" VerticalAlignment="Center"/> <Border.Transitions> <Transitions> <DoubleTransition Property="Opacity" Duration="0:0:0.3" Easing="SineEaseInOut"/> </Transitions> </Border.Transitions> </Border> <!-- Back content --> <Border x:Name="PART_BackHost" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding CornerRadius}" Background="#FFF3E0" Opacity="0"> <ContentPresenter Content="{TemplateBinding BackContent}" HorizontalAlignment="Center" VerticalAlignment="Center"/> <Border.Transitions> <Transitions> <DoubleTransition Property="Opacity" Duration="0:0:0.3" Easing="SineEaseInOut"/> </Transitions> </Border.Transitions> </Border> <!-- Flip button --> <ToggleButton x:Name="PART_FlipButton" Grid.Row="1" Width="20" Height="20" Margin="0,5,0,5" HorizontalAlignment="Center" VerticalAlignment="Center"> <ToggleButton.Template> <ControlTemplate> <Grid> <Ellipse Stroke="#555" Fill="WhiteSmoke" StrokeThickness="0.5"/> <Path Data="M4,5 L7,6.5 L4,8 Z" Margin="2,0,0,0" Fill="#455A64" Height="15" Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> </ControlTemplate> </ToggleButton.Template> <ToggleButton.RenderTransform> <Rotate3DTransform AngleY="{Binding FlipAngle, RelativeSource={RelativeSource TemplatedParent}}"> <Rotate3DTransform.Transitions> <Transitions> <DoubleTransition Property="AngleY" Duration="0:0:0.3" Easing="SineEaseInOut"/> </Transitions> </Rotate3DTransform.Transitions> </Rotate3DTransform> </ToggleButton.RenderTransform> </ToggleButton> </Grid> </ControlTemplate> </Setter.Value> </Setter> <!-- flipped 状态样式 --> <Style Selector="^:flipped /template/ Border#PART_FrontHost"> <Setter Property="Opacity" Value="0"/> <Setter Property="IsHitTestVisible" Value="False"/> </Style> <Style Selector="^:flipped /template/ Border#PART_BackHost"> <Setter Property="Opacity" Value="1"/> <Setter Property="IsHitTestVisible" Value="True"/> </Style> <Style Selector="^:not(:flipped) /template/ Border#PART_FrontHost"> <Setter Property="IsHitTestVisible" Value="True"/> </Style> <Style Selector="^:not(:flipped) /template/ Border#PART_BackHost"> <Setter Property="IsHitTestVisible" Value="False"/> </Style> <!-- 旋转角度 --> <Style Selector="^:flipped" x:SetterTargetType="local:FlipPanel2"> <Setter Property="local:FlipPanel2.FlipAngle" Value="180"/> </Style> </Style> </Styles>
FlipPanelTest.axaml代码
<Window xmlns="https://github.com/avaloniaui" 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" xmlns:local="using:AvaloniaUI" Height="300" Width="300" x:Class="AvaloniaUI.FlipPanelTest" Title="FlipPanelTest"> <Grid Background="Transparent"> <local:FlipPanel2 x:Name="panel" BorderBrush="DarkOrange" BorderThickness="3" IsFlipped="True" CornerRadius="4" Margin="10"> <!-- Front content --> <local:FlipPanel2.FrontContent> <StackPanel Margin="6"> <StackPanel.Styles> <Style Selector="Button"> <Setter Property="HorizontalAlignment" Value="Center"/> <Setter Property="Padding" Value="3"/> <Setter Property="Margin" Value="3"/> </Style> </StackPanel.Styles> <TextBlock Text="This is the front side of the FlipPanel." TextWrapping="Wrap" Margin="3" FontSize="16" Foreground="DarkOrange"/> <Button Content="Button One"/> <Button Content="Button Two"/> <Button Content="Button Three"/> <Button Content="Button Four"/> </StackPanel> </local:FlipPanel2.FrontContent> <!-- Back content --> <local:FlipPanel2.BackContent> <Grid Margin="6" RowDefinitions="auto,*"> <TextBlock Text="This is the back side of the FlipPanel." TextWrapping="Wrap" Margin="3" FontSize="16" Foreground="DarkMagenta"/> <Button Grid.Row="1" Margin="3" Padding="10" Content="Flip Back to Front" HorizontalAlignment="Center" VerticalAlignment="Center" Click="cmdFlip_Click"/> </Grid> </local:FlipPanel2.BackContent> </local:FlipPanel2> </Grid> </Window>
FlipPanelTest.cs代码
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Shares.Avalonia;
namespace AvaloniaUI;
public partial class FlipPanelTest : Window
{
public FlipPanelTest()
{
InitializeComponent();
this.Load("avares://AvaloniaUI/Demos/Book/18/CustomControls/FlipPanel.axaml");
}
private void cmdFlip_Click(object? sender, RoutedEventArgs e)
{
// 切换翻转状态
panel.IsFlipped = !panel.IsFlipped;
}
}
运行效果

浙公网安备 33010602011771号