初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器 HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块 Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚 AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
|
||||
using PCL.Core.App.Localization;
|
||||
namespace PCL;
|
||||
|
||||
public class MyComboBox : ComboBox
|
||||
{
|
||||
public delegate void TextChangedEventHandler(object sender, TextChangedEventArgs e);
|
||||
|
||||
public static readonly DependencyProperty HintTextProperty = DependencyProperty.Register("HintText", typeof(string),
|
||||
typeof(MyComboBox), new PropertyMetadata("", (d, e) =>
|
||||
{
|
||||
var c = (MyComboBox)d;
|
||||
if (c.textBox is not null)
|
||||
c.textBox.HintText = (string)e.NewValue;
|
||||
}));
|
||||
|
||||
private string _Text;
|
||||
|
||||
// 鼠标按下接口
|
||||
private bool isMouseDown;
|
||||
|
||||
// 修复 WPF Bug:下拉框文本修改后,依然误认为还选择着此前的选项,导致再次点击该选项时内容不变
|
||||
private bool isTextChanging;
|
||||
private double realWidth; // 由于下拉框 Popup 宽度与 Width 一致,故不能为 NaN(Auto)
|
||||
private MyTextBox textBox;
|
||||
|
||||
// 基础
|
||||
public int Uuid = ModBase.GetUuid();
|
||||
|
||||
public MyComboBox()
|
||||
{
|
||||
_Text = SelectedItem?.ToString() ?? "";
|
||||
PreviewMouseLeftButtonDown += MyComboBox_PreviewMouseLeftButtonDown;
|
||||
PreviewMouseLeftButtonUp += MyComboBox_PreviewMouseLeftButtonUp;
|
||||
MouseLeave += MyComboBox_PreviewMouseLeftButtonUp;
|
||||
IsEnabledChanged += (_, _) => RefreshColor();
|
||||
MouseEnter += (_, _) => RefreshColor();
|
||||
MouseLeave += (_, _) => RefreshColor();
|
||||
PreviewMouseLeftButtonDown += (_, _) => RefreshColor();
|
||||
PreviewMouseLeftButtonUp += (_, _) => RefreshColor();
|
||||
GotKeyboardFocus += (_, _) => RefreshColor();
|
||||
DropDownOpened += MyComboBox_DropDownOpened;
|
||||
DropDownClosed += MyComboBox_DropDownClosed;
|
||||
TextChanged += MyComboBox_TextChanged;
|
||||
}
|
||||
|
||||
public string HintText
|
||||
{
|
||||
get => (string)GetValue(HintTextProperty);
|
||||
set => SetValue(HintTextProperty, value);
|
||||
}
|
||||
|
||||
public new string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsEditable)
|
||||
{
|
||||
if (textBox is null) return _Text ?? "";
|
||||
return textBox.Text ?? "";
|
||||
}
|
||||
|
||||
return (SelectedItem ?? "").ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
if (IsEditable)
|
||||
{
|
||||
if (textBox is null)
|
||||
_Text = value;
|
||||
else
|
||||
textBox.Text = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("该 ComboBox 不支持修改文本。");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool DropDownWidthSync { get; set; } = true;
|
||||
|
||||
public ContentPresenter ContentPresenter => (ContentPresenter)Template.FindName("PART_Content", this);
|
||||
public event TextChangedEventHandler? TextChanged;
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
if (!IsEditable)
|
||||
return;
|
||||
try
|
||||
{
|
||||
textBox = (MyTextBox)Template.FindName("PART_EditableTextBox", this);
|
||||
textBox.AddHandler(LostFocusEvent, new RoutedEventHandler((_, _) => RefreshColor()));
|
||||
textBox.changedEventList.Add((sender, e) => TextChanged?.Invoke(sender, (TextChangedEventArgs)e));
|
||||
textBox.Tag = Tag; // 有时需要用文本框的 Tag 来写入设置
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
textBox.Text = _Text;
|
||||
else
|
||||
TextChanged?.Invoke(this, null);
|
||||
if (HintText.Length > 0)
|
||||
textBox.HintText = HintText;
|
||||
textBox.SetResourceReference(TextBoxBase.CaretBrushProperty, "ColorBrushGray1");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ModBase.Log(
|
||||
ex,
|
||||
"初始化可编辑文本框失败(" + (Name ?? "") + ")",
|
||||
ModBase.LogLevel.Feedback,
|
||||
userSummary: Lang.Text("Application.Control.Error.OperationFailed"));
|
||||
}
|
||||
}
|
||||
|
||||
private void MyComboBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
isMouseDown = true;
|
||||
}
|
||||
|
||||
private void MyComboBox_PreviewMouseLeftButtonUp(object sender, EventArgs e)
|
||||
{
|
||||
isMouseDown = false;
|
||||
}
|
||||
|
||||
// 指向动画
|
||||
public void RefreshColor()
|
||||
{
|
||||
// 判断当前颜色
|
||||
string foreColorName;
|
||||
string backColorName;
|
||||
int time;
|
||||
if (IsEnabled)
|
||||
{
|
||||
if (isMouseDown || IsDropDownOpen ||
|
||||
(IsEditable && ((MyTextBox)Template.FindName("PART_EditableTextBox", this)).IsFocused))
|
||||
{
|
||||
foreColorName = "ColorBrush3";
|
||||
backColorName = "ColorBrush7";
|
||||
time = 10;
|
||||
}
|
||||
else if (IsMouseOver)
|
||||
{
|
||||
foreColorName = "ColorBrush4";
|
||||
backColorName = "ColorBrush7";
|
||||
time = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreColorName = "ColorBrushBg0";
|
||||
backColorName = "ColorBrushHalfWhite";
|
||||
time = 100;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreColorName = "ColorBrushGray5";
|
||||
backColorName = "ColorBrushGray6";
|
||||
time = 200;
|
||||
}
|
||||
|
||||
// 触发颜色动画
|
||||
if (IsLoaded && ModAnimation.AniControlEnabled == 0) // 防止默认属性变更触发动画
|
||||
{
|
||||
// 有动画
|
||||
ModAnimation.AniStart(
|
||||
new[]
|
||||
{
|
||||
ModAnimation.AaColor(this, ForegroundProperty, foreColorName, time),
|
||||
ModAnimation.AaColor(this, BackgroundProperty, backColorName, time)
|
||||
}, "MyComboBox Color " + Uuid);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 无动画
|
||||
ModAnimation.AniStop("MyComboBox Color " + Uuid);
|
||||
SetResourceReference(ForegroundProperty, foreColorName);
|
||||
SetResourceReference(BackgroundProperty, backColorName);
|
||||
}
|
||||
}
|
||||
|
||||
private void MyComboBox_DropDownOpened(object sender, EventArgs e)
|
||||
{
|
||||
realWidth = Width;
|
||||
if (DropDownWidthSync)
|
||||
Width = ActualWidth;
|
||||
try
|
||||
{
|
||||
var popup = (Grid)Template.FindName("PanPopup", this);
|
||||
popup.Opacity = ModMain.frmMain.Opacity;
|
||||
if (!DropDownWidthSync)
|
||||
popup.MinWidth = ActualWidth;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ModBase.Log(
|
||||
ex,
|
||||
"设置下拉框属性失败",
|
||||
ModBase.LogLevel.Feedback,
|
||||
userSummary: Lang.Text("Application.Control.Error.OperationFailed"));
|
||||
}
|
||||
}
|
||||
|
||||
private void MyComboBox_DropDownClosed(object sender, EventArgs e)
|
||||
{
|
||||
Width = realWidth;
|
||||
}
|
||||
|
||||
private void MyComboBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (isTextChanging || !IsEditable)
|
||||
return;
|
||||
if (SelectedItem is null || Text == SelectedItem.ToString()) return;
|
||||
{
|
||||
var rawText = Text;
|
||||
var rawSelectionStart = textBox.SelectionStart;
|
||||
isTextChanging = true;
|
||||
SelectedItem = null;
|
||||
Text = rawText;
|
||||
textBox.SelectionStart = rawSelectionStart;
|
||||
isTextChanging = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 用于 ItemsSource 的自定义容器
|
||||
protected override DependencyObject GetContainerForItemOverride()
|
||||
{
|
||||
return new MyComboBoxItem();
|
||||
}
|
||||
|
||||
private void MyComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (IsLoaded && ModAnimation.AniControlEnabled == 0) ModMain.RaiseCustomEvent(this);
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item)
|
||||
{
|
||||
return item is MyComboBoxItem || base.IsItemItsOwnContainerOverride(item);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user