Files
MRCC/launcher/PCL-CE/Plain Craft Launcher 2/Controls/MyComboBox.cs
T

243 lines
7.7 KiB
C#
Raw Normal View History

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 一致,故不能为 NaNAuto
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);
}
}