1,创建翻转面板的资源字典:FlippPanel.xaml。
- 无外观控件同样必须给样式指定类型( <ControlTemplate TargetType="ss:FlipPanel">),相关详情参考:WPF之创建无外观控件-CSDN博客)。
XML
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ss="clr-namespace:无外观控件"
xmlns:local="clr-namespace:无外观控件.Themes">
<Style TargetType="ss:FlipPanel">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ss:FlipPanel">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<!--1,为给模板添加VisualStateManager元素,模板必须使用布局面板。布局面板包含控件的两个可视化对象和VisualStateManager元素(该元素不可见)-->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ViewStates">
<VisualStateGroup.Transitions>
<!--两个可视对象切换时间,以及伴随的ToggleButton切换动画-->
<VisualTransition To="Normal" GeneratedDuration="00:00:01">
<Storyboard >
<DoubleAnimation To="0" Storyboard.TargetName="PART_Rota" Storyboard.TargetProperty="Angle" ></DoubleAnimation>
</Storyboard>
</VisualTransition>
<VisualTransition To="Flipped" GeneratedDuration="00:00:2">
<Storyboard >
<DoubleAnimation To="180" Storyboard.TargetName="PART_Rota" Storyboard.TargetProperty="Angle" ></DoubleAnimation>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState Name="Normal">
<Storyboard >
<DoubleAnimation To="0" Storyboard.TargetName="front" Storyboard.TargetProperty="Opacity" Duration="00:00:00"></DoubleAnimation>
<!--ToggleButton旋转动画不能省,否则动画异常-->
<DoubleAnimation To="0" Storyboard.TargetName="PART_Rota" Storyboard.TargetProperty="Angle"></DoubleAnimation>
</Storyboard>
</VisualState>
<VisualState Name="Flipped">
<Storyboard >
<DoubleAnimation To="0" Storyboard.TargetName="back" Storyboard.TargetProperty="Opacity" Duration="00:00:00"></DoubleAnimation>
<!--ToggleButton旋转动画不能省,否则动画异常-->
<DoubleAnimation To="180" Storyboard.TargetName="PART_Rota" Storyboard.TargetProperty="Angle" Duration="00:00:00" ></DoubleAnimation>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="front" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{TemplateBinding CornerRadius}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<ContentPresenter Content="{TemplateBinding FrontContent}"></ContentPresenter>
</Border>
<Border x:Name="back" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{TemplateBinding CornerRadius}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<ContentPresenter Content="{TemplateBinding BackContent}"></ContentPresenter>
</Border>
<ToggleButton Grid.Row="1" Height="40" Name="FlipButton" RenderTransformOrigin="0.5,0.5">
<ToggleButton.RenderTransform>
<RotateTransform x:Name="PART_Rota" ></RotateTransform>
</ToggleButton.RenderTransform>
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<ToggleButton Grid.Column="1" Grid.Row="1" Name="FlipButton">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Rectangle >
<Rectangle.Fill>
<DrawingBrush Stretch="None">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="White">
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="2"></Pen>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup>
<EllipseGeometry RadiusX="15" RadiusY="15"></EllipseGeometry>
<CombinedGeometry GeometryCombineMode="Intersect">
<CombinedGeometry.Geometry1>
<EllipseGeometry RadiusX="7.5" RadiusY="7.5"></EllipseGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<PathGeometry Figures="M-7.5,0 L0,-7.5 L7.5,-7.5 L0,0 L7.5,7.5 L0,7.5 Z">
</PathGeometry>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
- VisualStateManager只能在布局面板下进行状态管理。
2,在generic.xaml中添加资源字典FlipPanel.xaml.
XML
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="无外观控件;component/Themes/colorpicker.xaml">
</ResourceDictionary>
<ResourceDictionary Source="无外观控件;component/Themes/FlipPanel.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
3,编写代码
cs
[TemplatePart(Name = "FlipButton", Type =typeof(ToggleButton))]//该特性只是进行提示,无其他意义,可舍去
[TemplateVisualState(GroupName = "Normal", Name = "ViewStates")]//该特性提示存在可视化切换,无其他实际意义,可舍去
[TemplateVisualState(GroupName = "Flipped", Name = "ViewStates")]
public class FlipPanel : Control
{
public static readonly DependencyProperty CornerRadiusProperty;
public static readonly DependencyProperty FrontContentProperty;
public static readonly DependencyProperty BackContentProperty;
public static readonly DependencyProperty IsFlippedProperty;
static FlipPanel()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FlipPanel), new FrameworkPropertyMetadata(typeof(FlipPanel)));
CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(FlipPanel));
FrontContentProperty = DependencyProperty.Register("FrontContent", typeof(object), typeof(FlipPanel));
BackContentProperty = DependencyProperty.Register("BackContent", typeof(object), typeof(FlipPanel));
IsFlippedProperty = DependencyProperty.Register("IsFlipped", typeof(bool), typeof(FlipPanel));
}
/// <summary>
/// 设置控件边框倒角
/// </summary>
public CornerRadius CornerRadius
{
get
{
return (CornerRadius)this.GetValue(CornerRadiusProperty);
}
set
{
this.SetValue(CornerRadiusProperty, value);
}
}
/// <summary>
/// 前置内容
/// </summary>
public object FrontContent
{
get
{
return this.GetValue(FrontContentProperty);
}
set
{
this.SetValue(FrontContentProperty, value);
}
}
/// <summary>
/// 后置内容
/// </summary>
public object BackContent
{
get
{
return GetValue(BackContentProperty);
}
set
{
this.SetValue(BackContentProperty, value);
}
}
/// <summary>
/// 是否翻转
/// </summary>
public bool IsFlipped
{
get
{
return (bool)GetValue(IsFlippedProperty);
}
set
{
SetValue(IsFlippedProperty, value);
ChangeVisualState(true);
}
}
public override void OnApplyTemplate()
{
ToggleButton btn = GetTemplateChild("FlipButton") as ToggleButton;
btn.Click += Btn_Click;
ChangeVisualState(false);
base.OnApplyTemplate();
}
private void Btn_Click(object sender, RoutedEventArgs e)
{
IsFlipped = !IsFlipped;
}
void ChangeVisualState(bool useTransition)
{
if (IsFlipped)
{
VisualStateManager.GoToState(this, "Flipped", useTransition);
}
else
{
VisualStateManager.GoToState(this, "Normal", useTransition);
}
}
}
4,在UI上添加控件
XML
<local:FlipPanel Grid.Row="1" IsFlipped="True">
<local:FlipPanel.FrontContent>
<StackPanel>
<Button Content="前1"></Button>
<Button Content="前2"></Button>
<Button Content="前3"></Button>
<Button Content="前3"></Button>
<Button Content="前4"></Button>
</StackPanel>
</local:FlipPanel.FrontContent>
<local:FlipPanel.BackContent>
<StackPanel>
<Button Content="后1"></Button>
</StackPanel>
</local:FlipPanel.BackContent>
</local:FlipPanel>
5,效果
6,Demo 链接
https://download.csdn.net/download/lingxiao16888/89253829?spm=1001.2014.3001.5501