Files
HandyControl/src/Shared/HandyControl_Shared/Controls/Block/RunningBlock/RunningBlock.cs
T
2022-10-10 23:15:48 +08:00

199 lines
6.7 KiB
C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using HandyControl.Data;
using HandyControl.Expression.Drawing;
namespace HandyControl.Controls;
[TemplatePart(Name = ElementContent, Type = typeof(FrameworkElement))]
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
public class RunningBlock : ContentControl
{
private const string ElementContent = "PART_ContentElement";
private const string ElementPanel = "PART_Panel";
protected Storyboard _storyboard;
private FrameworkElement _elementContent;
private FrameworkElement _elementPanel;
public override void OnApplyTemplate()
{
if (_elementPanel != null)
{
_elementPanel.SizeChanged -= ElementPanel_SizeChanged;
}
base.OnApplyTemplate();
_elementContent = GetTemplateChild(ElementContent) as FrameworkElement;
_elementPanel = GetTemplateChild(ElementPanel) as Panel;
if (_elementPanel != null)
{
_elementPanel.SizeChanged += ElementPanel_SizeChanged;
}
UpdateContent();
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
UpdateContent();
}
private void ElementPanel_SizeChanged(object sender, SizeChangedEventArgs e) => UpdateContent();
public static readonly DependencyProperty RunawayProperty = DependencyProperty.Register(
nameof(Runaway), typeof(bool), typeof(RunningBlock), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.AffectsRender));
public bool Runaway
{
get => (bool) GetValue(RunawayProperty);
set => SetValue(RunawayProperty, ValueBoxes.BooleanBox(value));
}
public static readonly DependencyProperty AutoRunProperty = DependencyProperty.Register(
nameof(AutoRun), typeof(bool), typeof(RunningBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender));
public bool AutoRun
{
get => (bool) GetValue(AutoRunProperty);
set => SetValue(AutoRunProperty, ValueBoxes.BooleanBox(value));
}
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
nameof(Orientation), typeof(Orientation), typeof(RunningBlock), new FrameworkPropertyMetadata(default(Orientation), FrameworkPropertyMetadataOptions.AffectsRender));
public Orientation Orientation
{
get => (Orientation) GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register(
nameof(Duration), typeof(Duration), typeof(RunningBlock), new FrameworkPropertyMetadata(new Duration(TimeSpan.FromSeconds(5)), FrameworkPropertyMetadataOptions.AffectsRender));
public Duration Duration
{
get => (Duration) GetValue(DurationProperty);
set => SetValue(DurationProperty, value);
}
public static readonly DependencyProperty SpeedProperty = DependencyProperty.Register(
nameof(Speed), typeof(double), typeof(RunningBlock), new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsRender));
public double Speed
{
get => (double) GetValue(SpeedProperty);
set => SetValue(SpeedProperty, value);
}
public static readonly DependencyProperty IsRunningProperty = DependencyProperty.Register(
nameof(IsRunning), typeof(bool), typeof(RunningBlock), new PropertyMetadata(ValueBoxes.TrueBox, (o, args) =>
{
var ctl = (RunningBlock) o;
var v = (bool) args.NewValue;
if (v)
{
ctl._storyboard?.Resume();
}
else
{
ctl._storyboard?.Pause();
}
}));
public bool IsRunning
{
get => (bool) GetValue(IsRunningProperty);
set => SetValue(IsRunningProperty, ValueBoxes.BooleanBox(value));
}
public static readonly DependencyProperty AutoReverseProperty = DependencyProperty.Register(
nameof(AutoReverse), typeof(bool), typeof(RunningBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender));
public bool AutoReverse
{
get => (bool) GetValue(AutoReverseProperty);
set => SetValue(AutoReverseProperty, ValueBoxes.BooleanBox(value));
}
private void UpdateContent()
{
if (_elementContent == null || _elementPanel == null) return;
if (MathHelper.IsZero(_elementPanel.ActualWidth) || MathHelper.IsZero(_elementPanel.ActualHeight)) return;
_storyboard?.Stop();
double from;
double to;
PropertyPath propertyPath;
if (Orientation == Orientation.Horizontal)
{
if (AutoRun && _elementPanel.ActualWidth < ActualWidth)
{
return;
}
if (Runaway)
{
from = -_elementPanel.ActualWidth;
to = ActualWidth;
}
else
{
from = 0;
to = ActualWidth - _elementPanel.ActualWidth;
SetCurrentValue(AutoReverseProperty, ValueBoxes.TrueBox);
}
propertyPath = new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)");
}
else
{
if (AutoRun && _elementPanel.ActualHeight < ActualHeight)
{
return;
}
if (Runaway)
{
from = -_elementPanel.ActualHeight;
to = ActualHeight;
}
else
{
from = 0;
to = ActualHeight - _elementPanel.ActualHeight;
SetCurrentValue(AutoReverseProperty, ValueBoxes.TrueBox);
}
propertyPath = new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.Y)");
}
var duration = double.IsNaN(Speed)
? Duration
: !MathHelper.IsVerySmall(Speed)
? TimeSpan.FromSeconds(Math.Abs(to - from) / Speed)
: Duration;
var animation = new DoubleAnimation(from, to, duration)
{
RepeatBehavior = RepeatBehavior.Forever,
AutoReverse = AutoReverse
};
Storyboard.SetTargetProperty(animation, propertyPath);
Storyboard.SetTarget(animation, _elementContent);
_storyboard = new Storyboard();
_storyboard.Children.Add(animation);
_storyboard.Begin();
}
}