Files
MRCC/launcher/PCL-CE/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.cs
T
xyou f70b061d1a
CI / Go Backend (push) Canceled after 0s
feat: 项目初始化 + 3D方块世界原型 + AI助搭系统
初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器

HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块

Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚

AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
2026-08-08 14:07:56 +08:00

430 lines
16 KiB
C#

using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Media;
namespace PCL;
[ContentProperty("Inlines")]
public partial class MyCheckBox
{
public delegate void ChangeEventHandler(object sender, bool user);
public delegate void PreviewChangeEventHandler(object sender, ModBase.RouteEventArgs e);
private const int animationTimeOfCheck = 150; // 勾选状态变更动画长度
// 指向动画
private const int animationTimeOfMouseIn = 100;
private const int animationTimeOfMouseOut = 200;
// 在使用 XAML 设置 Checked 属性时,不会触发 Checked_Set 方法,所以需要在这里手动触发 UI 改变
public static readonly DependencyProperty CheckedProperty = DependencyProperty.Register("Checked", typeof(bool?),
typeof(MyCheckBox), new PropertyMetadata(false, (d, e) =>
{
var obj = (MyCheckBox)d;
if (!obj.IsLoaded) obj.SyncUI();
}));
/// <summary>
/// 是否为三态复选框。
/// </summary>
public static readonly DependencyProperty IsThreeStateProperty =
DependencyProperty.Register("IsThreeState", typeof(bool), typeof(MyCheckBox), new PropertyMetadata(false));
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string),
typeof(MyCheckBox), new PropertyMetadata((sender, e) =>
{
if (sender is not null) ((MyCheckBox)sender).LabText.Text = (string)e.NewValue;
}));
private bool? _previousState = false; // 上一次的勾选状态
private bool allowMouseDown = true;
// 点击事件
private bool mouseDowned;
// 基础
public int Uuid = ModBase.GetUuid();
public MyCheckBox()
{
InitializeComponent();
MouseLeftButtonUp += (_, _) => Checkbox_MouseUp();
MouseLeftButtonDown += (_, _) => Checkbox_MouseDown();
MouseLeave += (_, _) => Checkbox_MouseLeave();
IsEnabledChanged += (_, _) => Checkbox_IsEnabledChanged();
MouseEnter += (_, _) => Checkbox_MouseEnterAnimation();
MouseLeave += (_, _) => Checkbox_MouseLeaveAnimation();
}
// 自定义属性
public bool? Checked
{
get => (bool?)GetValue(CheckedProperty);
set => SetChecked(value, false);
}
public bool IsThreeState
{
get => (bool)GetValue(IsThreeStateProperty);
set => SetValue(IsThreeStateProperty, value);
} // 是否为三态复选框
public InlineCollection Inlines => LabText.Inlines;
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
} // 内容
/// <summary>
/// 复选框勾选状态改变。
/// </summary>
/// <param name="user">是否为用户手动改变的勾选状态。</param>
public event ChangeEventHandler? Change;
public event PreviewChangeEventHandler? PreviewChange;
/// <summary>
/// 手动设置 Checked 属性。
/// </summary>
/// <param name="value">新的 Checked 属性。</param>
/// <param name="user">是否由用户引发。</param>
public void SetChecked(bool? value, bool user)
{
try
{
if (Checked.HasValue && value.HasValue && Checked.Value == value.Value)
return;
// Preview 事件
if (value.HasValue && value.Value && user)
{
var e = new ModBase.RouteEventArgs(user);
PreviewChange?.Invoke(this, e);
if (e.handled)
{
mouseDowned = true;
Checkbox_MouseLeave();
mouseDowned = false;
return;
}
}
// 判断真实勾选状态
var isChecked = GetFinalState(value, IsThreeState);
_previousState = Checked; // 记录上一次的勾选状态
SetValue(CheckedProperty, isChecked);
if (IsLoaded)
Change?.Invoke(this, user);
// 更改动画
SyncUI();
ModMain.RaiseCustomEvent(this);
}
catch (Exception ex)
{
ModBase.Log(ex, "设置 Checked 失败");
}
}
private void SyncUI()
{
if (ControlVisualHelpers.ShouldAnimate(this)) // 防止默认属性变更触发动画
{
allowMouseDown = false;
var isChecked = GetFinalState(Checked, IsThreeState);
switch (isChecked, _previousState)
{
case (true, null):
AniBackgroundScale();
AniIndeterminateHide();
AniCheckShow();
AniColorChecked();
AniAllowMouseDown();
break;
case (true, false):
AniBackgroundScale();
AniCheckShow();
AniColorChecked();
AniAllowMouseDown();
break;
case (false, true):
AniBackgroundScale();
AniCheckHide();
AniColorUnchecked();
AniAllowMouseDown();
break;
case (false, null):
AniBackgroundScale();
AniIndeterminateHide();
AniCheckHide();
AniColorUnchecked();
AniAllowMouseDown();
break;
case (null, true):
AniBackgroundScale();
AniCheckHide();
AniIndeterminateShow();
AniColorUnchecked();
AniAllowMouseDown();
break;
case (null, false):
AniBackgroundScale();
AniIndeterminateShow();
AniColorUnchecked();
AniAllowMouseDown();
break;
}
}
else
{
// 不使用动画
ModAnimation.AniStop("MyCheckBox Background Scale " + Uuid);
ModAnimation.AniStop("MyCheckBox Check Scale Show" + Uuid);
ModAnimation.AniStop("MyCheckBox Check Scale Hide" + Uuid);
ModAnimation.AniStop("MyCheckBox Indeterminate Scale Show" + Uuid);
ModAnimation.AniStop("MyCheckBox Indeterminate Scale Hide" + Uuid);
ModAnimation.AniStop("MyCheckBox BorderColor " + Uuid);
ModAnimation.AniStop("MyCheckBox AllowMouseDown " + Uuid);
if (Checked == true)
{
((ScaleTransform)ShapeCheck.RenderTransform).ScaleX = 1d;
((ScaleTransform)ShapeCheck.RenderTransform).ScaleY = 1d;
ShapeBorder.SetResourceReference(Border.BorderBrushProperty,
IsEnabled ? "ColorBrush2" : "ColorBrushGray4");
}
else
{
((ScaleTransform)ShapeCheck.RenderTransform).ScaleX = 0d;
((ScaleTransform)ShapeCheck.RenderTransform).ScaleY = 0d;
ShapeBorder.SetResourceReference(Border.BorderBrushProperty,
IsEnabled ? "ColorBrush1" : "ColorBrushGray4");
}
}
}
private void Checkbox_MouseUp()
{
if (!mouseDowned)
return;
ModBase.Log("[Control] 按下复选框(" + !Checked + "):" + Text);
mouseDowned = false;
if (IsThreeState)
{
switch (Checked)
{
case true:
SetChecked(null, true);
break;
case false:
SetChecked(true, true);
break;
case null:
SetChecked(false, true);
break;
}
ModAnimation.AniStart(
ModAnimation.AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100),
"MyCheckBox Background " + Uuid);
return;
}
SetChecked(!Checked, true);
ModAnimation.AniStart(ModAnimation.AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100),
"MyCheckBox Background " + Uuid);
}
private void Checkbox_MouseDown()
{
if (!allowMouseDown)
return;
mouseDowned = true;
Focus();
ModAnimation.AniStart(ModAnimation.AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushBg1", 100),
"MyCheckBox Background " + Uuid);
var scaleAnims = new List<ModAnimation.AniData>
{
ModAnimation.AaScale(ShapeBorder, 16.5d - ShapeBorder.Width, 1000,
ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong), absolute: true)
};
if (Checked == true)
scaleAnims.Add(ModAnimation.AaScaleTransform(ShapeCheck,
0.9d - ((ScaleTransform)ShapeCheck.RenderTransform).ScaleX, 1000,
ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong)));
ModAnimation.AniStart(scaleAnims.ToArray(), "MyCheckBox Scale " + Uuid);
}
private void Checkbox_MouseLeave()
{
if (!mouseDowned)
return;
mouseDowned = false;
ModAnimation.AniStart(ModAnimation.AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100),
"MyCheckBox Background " + Uuid);
var scaleAnims = new List<ModAnimation.AniData>
{
ModAnimation.AaScale(ShapeBorder, 18d - ShapeBorder.Width,
ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong), absolute: true)
};
if (Checked == true)
scaleAnims.Add(ModAnimation.AaScaleTransform(ShapeCheck, 1d - ((ScaleTransform)ShapeCheck.RenderTransform).ScaleX,
500, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong)));
ModAnimation.AniStart(scaleAnims.ToArray(), "MyCheckBox Scale " + Uuid);
}
private void Checkbox_IsEnabledChanged()
{
if (IsLoaded && ModAnimation.AniControlEnabled == 0) // 防止默认属性变更触发动画
{
// 有动画
if (IsEnabled)
{
// 可用
Checkbox_MouseLeaveAnimation();
}
else
{
// 不可用
ModAnimation.AniStart(
ModAnimation.AaColor(ShapeBorder, Border.BorderBrushProperty,
ThemeManager.colorGray4 - ShapeBorder.BorderBrush, animationTimeOfMouseOut),
"MyCheckBox BorderColor " + Uuid);
ModAnimation.AniStart(
ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty,
ThemeManager.colorGray4 - LabText.Foreground, animationTimeOfMouseOut),
"MyCheckBox TextColor " + Uuid);
}
}
else
{
// 无动画
ModAnimation.AniStop("MyCheckBox TextColor " + Uuid);
ModAnimation.AniStop("MyCheckBox BorderColor " + Uuid);
LabText.SetResourceReference(TextBlock.ForegroundProperty, IsEnabled ? "ColorBrush1" : "ColorBrushGray4");
ShapeBorder.SetResourceReference(Border.BorderBrushProperty,
IsEnabled ? Checked == true ? "ColorBrush2" : "ColorBrush1" : "ColorBrushGray4");
}
}
private void Checkbox_MouseEnterAnimation()
{
ModAnimation.AniStart(
ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", animationTimeOfMouseIn),
"MyCheckBox TextColor " + Uuid);
ModAnimation.AniStart(
ModAnimation.AaColor(ShapeBorder, Border.BorderBrushProperty, "ColorBrush3", animationTimeOfMouseIn),
"MyCheckBox BorderColor " + Uuid);
}
private void Checkbox_MouseLeaveAnimation()
{
if (!IsEnabled)
return; // MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误
ModAnimation.AniStart(
ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty,
IsEnabled ? "ColorBrush1" : "ColorBrushGray4", animationTimeOfMouseOut),
"MyCheckBox TextColor " + Uuid);
ModAnimation.AniStart(
ModAnimation.AaColor(ShapeBorder, Border.BorderBrushProperty,
IsEnabled ? Checked == true ? "ColorBrush2" : "ColorBrush1" : "ColorBrushGray4",
animationTimeOfMouseOut),
"MyCheckBox BorderColor " + Uuid);
}
// 动画
private void AniBackgroundScale()
{
ModAnimation.AniStart(
new[]
{
ModAnimation.AaScale(ShapeBorder, 12d - ShapeBorder.Width, animationTimeOfCheck,
ease: new ModAnimation.AniEaseOutFluent(), absolute: true),
ModAnimation.AaScale(ShapeBorder, 6d, animationTimeOfCheck * 2,
(int)Math.Round(animationTimeOfCheck * 0.7d), new ModAnimation.AniEaseOutBack(), absolute: true)
}, "MyCheckBox Background Scale " + Uuid);
}
private void AniCheckShow()
{
ModAnimation.AniStart(
ModAnimation.AaScaleTransform(ShapeCheck, 1d - ((ScaleTransform)ShapeCheck.RenderTransform).ScaleX,
animationTimeOfCheck * 2, (int)Math.Round(animationTimeOfCheck * 0.7d),
new ModAnimation.AniEaseOutBack(ModAnimation.AniEasePower.Weak)),
"MyCheckBox Check Scale Show" + Uuid);
}
private void AniCheckHide()
{
ModAnimation.AniStart(
ModAnimation.AaScaleTransform(ShapeCheck, -((ScaleTransform)ShapeCheck.RenderTransform).ScaleX,
(int)Math.Round(animationTimeOfCheck * 0.9d),
ease: new ModAnimation.AniEaseInFluent(ModAnimation.AniEasePower.Weak)),
"MyCheckBox Check Scale Hide" + Uuid);
}
private void AniIndeterminateShow()
{
ModAnimation.AniStart(
ModAnimation.AaScaleTransform(ShapeIndeterminate,
1d - ((ScaleTransform)ShapeIndeterminate.RenderTransform).ScaleX, animationTimeOfCheck * 2,
(int)Math.Round(animationTimeOfCheck * 0.7d),
new ModAnimation.AniEaseOutBack(ModAnimation.AniEasePower.Weak)),
"MyCheckBox Indeterminate Scale Show" + Uuid);
}
private void AniIndeterminateHide()
{
ModAnimation.AniStart(
ModAnimation.AaScaleTransform(ShapeIndeterminate,
-((ScaleTransform)ShapeIndeterminate.RenderTransform).ScaleX,
(int)Math.Round(animationTimeOfCheck * 0.9d),
ease: new ModAnimation.AniEaseInFluent(ModAnimation.AniEasePower.Weak)),
"MyCheckBox Indeterminate Scale Hide" + Uuid);
}
private void AniAllowMouseDown()
{
ModAnimation.AniStart(ModAnimation.AaCode(() => allowMouseDown = true, animationTimeOfCheck * 2),
"MyCheckBox AllowMouseDown " + Uuid);
}
private void AniColorChecked()
{
ModAnimation.AniStart(
ModAnimation.AaColor(ShapeBorder, Border.BorderBrushProperty,
IsEnabled ? IsMouseOver ? "ColorBrush3" : "ColorBrush2" : "ColorBrushGray4", animationTimeOfCheck),
"MyCheckBox BorderColor " + Uuid);
}
private void AniColorUnchecked()
{
ModAnimation.AniStart(
ModAnimation.AaColor(ShapeBorder, Border.BorderBrushProperty,
IsEnabled ? IsMouseOver ? "ColorBrush3" : "ColorBrush1" : "ColorBrushGray4", animationTimeOfCheck),
"MyCheckBox BorderColor " + Uuid);
}
private static bool? GetFinalState(bool? value, bool isThreeState)
{
return isThreeState ? value : value == true;
}
}