285 lines
8.8 KiB
C#
285 lines
8.8 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Animation;
|
|
using System.Windows.Media.Media3D;
|
|
using HandyControl.Data;
|
|
|
|
namespace HandyControl.Controls
|
|
{
|
|
public class FlipNumber : Viewport3D
|
|
{
|
|
private bool _isLoaded;
|
|
|
|
private TextBlock _page1TextDown;
|
|
|
|
private TextBlock _page2TextUp;
|
|
|
|
private TextBlock _page2TextDown;
|
|
|
|
private TextBlock _page3TextUp;
|
|
|
|
private ContainerUIElement3D _page1;
|
|
|
|
private ContainerUIElement3D _page2;
|
|
|
|
private ContainerUIElement3D _page3;
|
|
|
|
private ContainerUIElement3D _content;
|
|
|
|
private readonly AxisAngleRotation3D _pageRotation3D;
|
|
|
|
private readonly DoubleAnimation _animation;
|
|
|
|
private bool _isAnimating;
|
|
|
|
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
|
|
"CornerRadius", typeof(CornerRadius), typeof(FlipNumber), new PropertyMetadata(new CornerRadius(4)));
|
|
|
|
public CornerRadius CornerRadius
|
|
{
|
|
get => (CornerRadius) GetValue(CornerRadiusProperty);
|
|
set => SetValue(CornerRadiusProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register(
|
|
"Background", typeof(Brush), typeof(FlipNumber), new PropertyMetadata(default(Brush)));
|
|
|
|
public Brush Background
|
|
{
|
|
get => (Brush) GetValue(BackgroundProperty);
|
|
set => SetValue(BackgroundProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
|
|
"Foreground", typeof(Brush), typeof(FlipNumber), new PropertyMetadata(default(Brush)));
|
|
|
|
public Brush Foreground
|
|
{
|
|
get => (Brush) GetValue(ForegroundProperty);
|
|
set => SetValue(ForegroundProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
|
|
"FontSize", typeof(double), typeof(FlipNumber), new PropertyMetadata(70.0));
|
|
|
|
[TypeConverter(typeof(FontSizeConverter))]
|
|
public double FontSize
|
|
{
|
|
get => (double) GetValue(FontSizeProperty);
|
|
set => SetValue(FontSizeProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty NumberProperty = DependencyProperty.Register(
|
|
"Number", typeof(int), typeof(FlipNumber), new PropertyMetadata(ValueBoxes.Int0Box, OnNumberChanged));
|
|
|
|
private static void OnNumberChanged(DependencyObject s, DependencyPropertyChangedEventArgs e) =>
|
|
((FlipNumber) s).OnNumberChanged();
|
|
|
|
public int Number
|
|
{
|
|
get => (int) GetValue(NumberProperty);
|
|
set => SetValue(NumberProperty, value);
|
|
}
|
|
|
|
public FlipNumber()
|
|
{
|
|
var visual3D = new ModelVisual3D
|
|
{
|
|
Content = new DirectionalLight()
|
|
};
|
|
Children.Add(visual3D);
|
|
|
|
_pageRotation3D = new AxisAngleRotation3D
|
|
{
|
|
Angle = 0,
|
|
Axis = new Vector3D(1, 0, 0)
|
|
};
|
|
|
|
_animation = new DoubleAnimation(0, 180, new Duration(TimeSpan.FromSeconds(0.8)))
|
|
{
|
|
FillBehavior = FillBehavior.Stop
|
|
};
|
|
_animation.Completed += Animation_Completed;
|
|
|
|
Loaded += (s, e) =>
|
|
{
|
|
if (_isLoaded) return;
|
|
_isLoaded = true;
|
|
InitNumber();
|
|
var transform3D = new RotateTransform3D(_pageRotation3D);
|
|
_page2.Transform = transform3D;
|
|
};
|
|
}
|
|
|
|
private void Animation_Completed(object sender, EventArgs e)
|
|
{
|
|
_isAnimating = false;
|
|
UpdateNumber();
|
|
}
|
|
|
|
private void InitNumber()
|
|
{
|
|
_page1 = new ContainerUIElement3D();
|
|
var num1 = Number > 8 ? 0 : Number + 1;
|
|
var page1NumDown = CreateNumber(num1, false, out _page1TextDown);
|
|
_page1.Children.Add(page1NumDown);
|
|
|
|
_page2 = new ContainerUIElement3D();
|
|
var page2NumUp = CreateNumber(num1, true, out _page2TextUp);
|
|
var page2NumDown = CreateNumber(Number, false, out _page2TextDown);
|
|
_page2.Children.Add(page2NumUp);
|
|
_page2.Children.Add(page2NumDown);
|
|
|
|
_page3 = new ContainerUIElement3D();
|
|
var page3NumUp = CreateNumber(Number, true, out _page3TextUp);
|
|
_page3.Children.Add(page3NumUp);
|
|
var transform3D = new RotateTransform3D(new AxisAngleRotation3D
|
|
{
|
|
Angle = 180,
|
|
Axis = new Vector3D(1, 0, 0)
|
|
});
|
|
_page3.Transform = transform3D;
|
|
|
|
_content = new ContainerUIElement3D
|
|
{
|
|
Children =
|
|
{
|
|
_page1,
|
|
_page2,
|
|
_page3
|
|
}
|
|
};
|
|
Children.Add(_content);
|
|
}
|
|
|
|
private bool CheckNull() => _page1TextDown != null && _page2TextUp != null && _page2TextDown != null && _page3TextUp != null;
|
|
|
|
private void OnNumberChanged()
|
|
{
|
|
if (!CheckNull()) return;
|
|
|
|
InitNewNumber();
|
|
|
|
if (_isAnimating)
|
|
{
|
|
_isAnimating = false;
|
|
UpdateNumber();
|
|
return;
|
|
}
|
|
|
|
_isAnimating = true;
|
|
_pageRotation3D.BeginAnimation(AxisAngleRotation3D.AngleProperty, _animation);
|
|
}
|
|
|
|
private void InitNewNumber()
|
|
{
|
|
var num1 = Number.ToString();
|
|
_page1TextDown.Text = num1;
|
|
_page2TextUp.Text = num1;
|
|
}
|
|
|
|
private void UpdateNumber()
|
|
{
|
|
_pageRotation3D.BeginAnimation(AxisAngleRotation3D.AngleProperty, null);
|
|
_pageRotation3D.Angle = 0;
|
|
|
|
var num = Number.ToString();
|
|
_page2TextDown.Text = num;
|
|
_page3TextUp.Text = num;
|
|
|
|
_isAnimating = false;
|
|
}
|
|
|
|
private Viewport2DVisual3D CreateNumber(int num, bool isUp, out TextBlock textBlock)
|
|
{
|
|
int flag;
|
|
var rotateTransform = new RotateTransform();
|
|
|
|
if (isUp)
|
|
{
|
|
flag = -1;
|
|
rotateTransform.Angle = 180;
|
|
}
|
|
else
|
|
{
|
|
flag = 1;
|
|
}
|
|
var halfWidth = ActualWidth / 2;
|
|
var quarterWidth = ActualWidth / 4;
|
|
var quarterHeight = ActualHeight / 4;
|
|
|
|
var meMaterial = new DiffuseMaterial();
|
|
Viewport2DVisual3D.SetIsVisualHostMaterial(meMaterial, true);
|
|
|
|
textBlock = new TextBlock
|
|
{
|
|
RenderTransformOrigin = new Point(0.5, 0.5),
|
|
Foreground = Foreground,
|
|
FontSize = FontSize,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
TextAlignment = TextAlignment.Center,
|
|
Text = num.ToString(),
|
|
RenderTransform = rotateTransform,
|
|
Margin = new Thickness(0, 0, 0, -quarterHeight),
|
|
FontFamily = new FontFamily("Consolas")
|
|
};
|
|
|
|
var border = new Border
|
|
{
|
|
ClipToBounds = true,
|
|
CornerRadius = new CornerRadius(CornerRadius.TopLeft, CornerRadius.TopRight, 0, 0),
|
|
Background = Background,
|
|
Width = halfWidth,
|
|
Height = quarterHeight,
|
|
Child = textBlock
|
|
};
|
|
|
|
var positions = new Point3DCollection
|
|
{
|
|
new(-quarterWidth * flag, quarterHeight, 0),
|
|
new(-quarterWidth * flag, 0, 0),
|
|
new(quarterWidth * flag, 0, 0),
|
|
new(quarterWidth * flag, quarterHeight, 0)
|
|
};
|
|
|
|
var triangleIndices = new Int32Collection
|
|
{
|
|
0,
|
|
1,
|
|
2,
|
|
0,
|
|
2,
|
|
3
|
|
};
|
|
|
|
var textureCoordinates = new PointCollection
|
|
{
|
|
new(0, 0),
|
|
new(0, 1),
|
|
new(1, 1),
|
|
new(1, 0)
|
|
};
|
|
|
|
var geometry3D = new MeshGeometry3D
|
|
{
|
|
Positions = positions,
|
|
TriangleIndices = triangleIndices,
|
|
TextureCoordinates = textureCoordinates
|
|
};
|
|
|
|
var child = new Viewport2DVisual3D
|
|
{
|
|
Geometry = geometry3D,
|
|
Visual = border,
|
|
Material = meMaterial
|
|
};
|
|
|
|
return child;
|
|
}
|
|
}
|
|
}
|