Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
76ac067
feat: Button 动画
Hill23333 Dec 11, 2025
6214bb4
Merge branch 'PCL-Community:dev' into feat/animation-replace
Hill23333 Dec 11, 2025
f1ae0ef
feat: MyCard 部分动画
Hill23333 Dec 12, 2025
19f0120
feat: 窗口进入退出动画
Hill23333 Dec 16, 2025
153933a
Merge branch 'PCL-Community:dev' into feat/animation-replace
Hill23333 Dec 25, 2025
b026830
Merge remote-tracking branch 'upstream/dev' into feat/animation-replace
Hill23333 Jan 7, 2026
c120548
feat: 替换掉 FormMain 内旧动画
Hill23333 Jan 12, 2026
2419ccf
perf: 更改 Frame 行为
Hill23333 Jan 15, 2026
4f17444
fix: 无动画
Hill23333 Jan 15, 2026
b60c0f4
feat: MyComboBox, MyComboBoxItem, MyExtraButton, MyExtraTextButton
Hill23333 Jan 16, 2026
eacf0a8
Merge remote-tracking branch 'origin/dev' into feat/animation-replace
Hill23333 Jan 18, 2026
238cf41
fix: MyExtraTextButton
Hill23333 Jan 18, 2026
74c86ba
chore: 忘提交了
Hill23333 Jan 18, 2026
793f832
feat: MyHint
Hill23333 Jan 19, 2026
9705ffa
Merge remote-tracking branch 'upstream/dev' into feat/animation-replace
Hill23333 Feb 3, 2026
87812d1
Merge branch 'PCL-Community:dev' into feat/animation-replace
Hill23333 Feb 10, 2026
87bf9ca
Merge branch 'PCL-Community:dev' into feat/animation-replace
Hill23333 Feb 17, 2026
2e4bf84
Merge branch 'PCL-Community:dev' into feat/animation-replace
Hill23333 Feb 21, 2026
26a576c
Merge branch 'dev' into feat/animation-replace
Hill23333 Feb 22, 2026
5324122
fix: PCL.Core.App -> PCL.Core.App.IoC
Hill23333 Apr 5, 2026
75ecdb0
chore: 回滚,为 C# 化铺路
Hill23333 Apr 5, 2026
65c0d83
chore: 遗漏的文件
Hill23333 Apr 5, 2026
3653d25
Merge branch 'dev' into feat/animation-replace
Hill23333 Apr 5, 2026
72408f4
perf: 泛型优化
Hill23333 Apr 5, 2026
56f3284
fix: 泛型实现
Hill23333 Apr 5, 2026
4b0a6a7
fix: typo
Hill23333 Apr 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions PCL.Core/UI/Animation/Animatable/ClrAnimatable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ public ClrAnimatable(

object? IAnimatable.GetValue() => GetValue();
void IAnimatable.SetValue(object? value) => SetValue((T)value!);
void IAnimatable.SetValue<TValue>(TValue value) => SetValue((T)(object)value!);
}
23 changes: 23 additions & 0 deletions PCL.Core/UI/Animation/Animatable/EmptyAnimatable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace PCL.Core.UI.Animation.Animatable;

public sealed class EmptyAnimatable : IAnimatable
{
public static EmptyAnimatable Instance { get; } = new();

private EmptyAnimatable() { }

public object? GetValue()
{
return null;
}

public void SetValue(object value)
{
// 空
}

public void SetValue<T>(T value)
{
// 空
}
}
1 change: 1 addition & 0 deletions PCL.Core/UI/Animation/Animatable/IAnimatable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ public interface IAnimatable
{
public object? GetValue();
public void SetValue(object value);
public void SetValue<T>(T value);
}
67 changes: 66 additions & 1 deletion PCL.Core/UI/Animation/Animatable/WpfAnimatable.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
using PCL.Core.UI.Animation.ValueProcessor;

namespace PCL.Core.UI.Animation.Animatable;
Expand Down Expand Up @@ -28,13 +30,76 @@ public sealed class WpfAnimatable(DependencyObject owner, DependencyProperty? pr

ArgumentNullException.ThrowIfNull(actualProperty);

return Owner.GetValue(actualProperty);
var value = Owner.GetValue(actualProperty);
return value switch
{
SolidColorBrush brush => (NColor)brush,
Color color => (NColor)color,
ScaleTransform scaleTransform => (NScaleTransform)scaleTransform,
RotateTransform rotateTransform => (NRotateTransform)rotateTransform,
_ => value
};
}

public void SetValue(object value)
{
value = ValueProcessorManager.Filter(value);
ArgumentNullException.ThrowIfNull(Property);

value = value switch
{
NColor color => Property.Name switch
{
"Color" => (Color)color,
_ => (SolidColorBrush)color
},
NScaleTransform st => (ScaleTransform)st,
NRotateTransform rt => (RotateTransform)rt,
_ => value
};

Owner.SetValue(Property, value);
}

public void SetValue<T>(T value)
{
value = ValueProcessorManager.Filter(value);
ArgumentNullException.ThrowIfNull(Property);
SetValueCore(value);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetValueCore<T>(T value)
{
ArgumentNullException.ThrowIfNull(Property);

if (typeof(T) == typeof(NColor))
{
var color = Unsafe.As<T, NColor>(ref value);

Owner.SetValue(
Property,
Property.Name == "Color"
? (Color)color
: (SolidColorBrush)color);

return;
}

if (typeof(T) == typeof(NScaleTransform))
{
var st = Unsafe.As<T, NScaleTransform>(ref value);
Owner.SetValue(Property, (ScaleTransform)st);
return;
}

if (typeof(T) == typeof(NRotateTransform))
{
var rt = Unsafe.As<T, NRotateTransform>(ref value);
Owner.SetValue(Property, (RotateTransform)rt);
return;
}

Owner.SetValue(Property, value!);
}
}
90 changes: 90 additions & 0 deletions PCL.Core/UI/Animation/Core/ActionAnimation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using PCL.Core.UI.Animation.Animatable;

namespace PCL.Core.UI.Animation.Core;

/// <summary>
/// 用于在动画系统中执行 Action。
/// </summary>
public class ActionAnimation : AnimationBase
{
public ActionAnimation() { }

public ActionAnimation(Action action) => Action = _ => action();

public ActionAnimation(Action<CancellationToken> action) => Action = action;

public Action<CancellationToken> Action { get; set; } = null!;
public override int CurrentFrame { get; set; }
public TimeSpan Delay { get; set; }

private CancellationTokenSource? _cts = new();
private TaskCompletionSource? _tcs;
private int _called = 0;

public override async Task<IAnimation> RunAsync(IAnimatable target)
{
ArgumentNullException.ThrowIfNull(Action);

_tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
_cts = new CancellationTokenSource();

var clone = (ActionAnimation)MemberwiseClone();
clone.Status = AnimationStatus.Running;

// 延迟
await Task.Delay(Delay);

Interlocked.Exchange(ref _called, 0);
_ = AnimationService.PushAnimationAsync(clone, target);
return await _tcs.Task.ContinueWith<IAnimation>(_ => clone);
}

public override IAnimation RunFireAndForget(IAnimatable target)
{
ArgumentNullException.ThrowIfNull(Action);

_cts = new CancellationTokenSource();

var clone = (ActionAnimation)MemberwiseClone();
clone.Status = AnimationStatus.Running;

_ = Task.Run(async () =>
{
// 延迟
await Task.Delay(Delay);

Interlocked.Exchange(ref _called, 0);
AnimationService.PushAnimationFireAndForget(clone, target);
});

return clone;
}

public override void Cancel()
{
Status = AnimationStatus.Canceled;
_cts?.Cancel();
_tcs?.TrySetCanceled();
}

public override IAnimationFrame? ComputeNextFrame(IAnimatable target)
{
if (Status is AnimationStatus.Canceled or AnimationStatus.Completed) return null;

if (Interlocked.CompareExchange(ref _called, 1, 0) == 0)
{
return new ActionAnimationFrame(() =>
{
Action(_cts!.Token);
Status = AnimationStatus.Completed;
_tcs?.TrySetResult();
});
}

return null;
}
}
10 changes: 10 additions & 0 deletions PCL.Core/UI/Animation/Core/ActionAnimationFrame.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace PCL.Core.UI.Animation.Core;

public struct ActionAnimationFrame(Action action) : IAnimationFrame
{
public Action Action { get; set; } = action;

public Action GetAction() => Action;
}
14 changes: 10 additions & 4 deletions PCL.Core/UI/Animation/Core/AnimationBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using PCL.Core.UI.Animation.Animatable;
Expand All @@ -7,13 +8,18 @@ namespace PCL.Core.UI.Animation.Core;

public abstract class AnimationBase : DependencyObject, IAnimation
{
public abstract bool IsCompleted { get; }
public string Name { get; set; } = string.Empty;
private volatile int _status = (int)AnimationStatus.NotStarted;
public AnimationStatus Status
{
get => (AnimationStatus)_status;
internal set => Interlocked.Exchange(ref _status, (int)value);
}
public abstract int CurrentFrame { get; set; }

public abstract Task RunAsync(IAnimatable target);
public abstract void RunFireAndForget(IAnimatable target);
public abstract Task<IAnimation> RunAsync(IAnimatable target);
public abstract IAnimation RunFireAndForget(IAnimatable target);
public abstract void Cancel();

public abstract IAnimationFrame? ComputeNextFrame(IAnimatable target);

public void RaiseStarted() => Started?.Invoke(this, EventArgs.Empty);
Expand Down
19 changes: 10 additions & 9 deletions PCL.Core/UI/Animation/Core/AnimationFrame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@

namespace PCL.Core.UI.Animation.Core;

public readonly struct AnimationFrame<T> : IAnimationFrame where T : struct
{
public IAnimatable Target { get; init; }
public T Value { get; init; }
public T StartValue { get; init; }
public T GetAbsoluteValue() => ValueProcessorManager.Add(StartValue, Value);

object IAnimationFrame.GetAbsoluteValue() => GetAbsoluteValue();
}
// public readonly struct AnimationFrame<T>(IAnimatable target, T value, T startValue) : IAnimationFrame
// {
// public IAnimatable Target { get; init; } = target;
// public T Value { get; init; } = value;
// public T StartValue { get; init; } = startValue;
// public T GetAbsoluteValue() => ValueProcessorManager.Add(StartValue, Value);
// object IAnimationFrame.StartValue => StartValue!;
// object IAnimationFrame.Value => Value!;
// object IAnimationFrame.GetAbsoluteValue() => GetAbsoluteValue()!;
// }
Loading
Loading