using System;
|
using System.ComponentModel;
|
using System.Windows;
|
using System.Windows.Controls;
|
using System.Windows.Input;
|
using System.Windows.Media;
|
|
namespace UILib
|
{
|
public class EditBox : Control
|
{
|
static EditBox()
|
{
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(EditBox), new FrameworkPropertyMetadata(typeof(EditBox)));
|
}
|
|
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
|
"Value",
|
typeof(object),
|
typeof(EditBox),
|
new FrameworkPropertyMetadata());
|
|
public static readonly DependencyProperty CanEditProperty = DependencyProperty.Register(
|
"CanEdit",
|
typeof(bool),
|
typeof(EditBox),
|
new FrameworkPropertyMetadata(true, new PropertyChangedCallback(OnCanEditPropertyChanged)));
|
|
public static DependencyProperty IsEditingProperty = DependencyProperty.Register(
|
"IsEditing",
|
typeof(bool),
|
typeof(EditBox),
|
new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsEditingPropertyChanged)));
|
|
public static DependencyProperty PreEditingProperty = DependencyProperty.Register(
|
"PreEditing",
|
typeof(Func<bool?>),
|
typeof(EditBox),
|
new FrameworkPropertyMetadata());
|
|
public static DependencyProperty PreSubmitProperty = DependencyProperty.Register(
|
"PreSubmit",
|
typeof(Func<object, object, bool>),
|
typeof(EditBox),
|
new FrameworkPropertyMetadata());
|
|
public static DependencyProperty SubmitedProperty = DependencyProperty.Register(
|
"Submited",
|
typeof(Action<EditBox, object, object>),
|
typeof(EditBox),
|
new FrameworkPropertyMetadata());
|
|
public static DependencyProperty ShowEmptyProperty = DependencyProperty.Register(
|
"ShowEmpty",
|
typeof(bool),
|
typeof(EditBox),
|
new FrameworkPropertyMetadata(false));
|
|
private static void OnCanEditPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
|
{
|
if (obj is EditBox eb && e.Property == CanEditProperty)
|
{
|
bool value = (bool)e.NewValue;
|
if (value)
|
{
|
eb.MouseDoubleClick += eb.EditBox_MouseDoubleClick;
|
}
|
else
|
{
|
eb.MouseDoubleClick -= eb.EditBox_MouseDoubleClick;
|
}
|
}
|
}
|
|
private static void OnIsEditingPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
|
{
|
if (obj is EditBox eb && e.Property == IsEditingProperty)
|
{
|
bool value = (bool)e.NewValue;
|
eb.editing.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
|
if (value)
|
{
|
eb.editing.Focus();
|
eb.editing.SelectAll();
|
eb.editing.KeyDown += eb.EditBox_KeyDown;
|
}
|
else
|
{
|
eb.editing.KeyDown -= eb.EditBox_KeyDown;
|
}
|
}
|
}
|
|
private TextBox editing;
|
public EditBox()
|
{
|
if (CanEdit)
|
{
|
this.MouseDoubleClick += EditBox_MouseDoubleClick;
|
}
|
this.Loaded += EditBox_Loaded;
|
}
|
|
private void EditBox_Loaded(object sender, RoutedEventArgs e)
|
{
|
editing = this.Template.FindName("PART_TextBoxPart", this) as TextBox;
|
}
|
|
private void EditBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
{
|
if (IsEditing)
|
{
|
return;
|
}
|
|
Func<bool?> pre = GetValue(PreEditingProperty) as Func<bool?>;
|
if (pre != null && pre.Invoke() != true)
|
{
|
return;
|
}
|
var win = Window.GetWindow(this);
|
|
win.MouseDown += EditBox_LostFocus;
|
editing.LostFocus += EditBox_LostFocus;
|
IsEditing = true;
|
e.Handled = true;
|
}
|
|
public static bool GetElementUnderMouse(UIElement relativeTo, UIElement target)
|
{
|
Point mousePosition = Mouse.GetPosition(relativeTo);
|
bool res = false;
|
HitTestResultCallback resultCallback = (result) =>
|
{
|
// 获取相交的UI元素
|
var element = result.VisualHit as FrameworkElement;
|
|
if (element != null && element == target)
|
{
|
res = true;
|
return HitTestResultBehavior.Stop; // 找到后停止遍历
|
}
|
return HitTestResultBehavior.Continue;
|
};
|
|
VisualTreeHelper.HitTest(relativeTo, null,
|
resultCallback, new PointHitTestParameters(mousePosition));
|
return res;
|
}
|
|
private void EditBox_LostFocus(object sender, RoutedEventArgs e)
|
{
|
CancelEditing(sender);
|
}
|
|
private void EditBox_KeyDown(object sender, KeyEventArgs e)
|
{
|
if (e.Key == Key.Enter)
|
{
|
CancelEditing(sender);
|
}
|
}
|
|
private void CancelEditing(object sender)
|
{
|
if (PreSubmit != null && !PreSubmit.Invoke(Value, DataContext))
|
{
|
return;
|
}
|
|
if (sender == editing)
|
{
|
IsEditing = false;
|
editing.LostFocus -= EditBox_LostFocus;
|
Window.GetWindow(this).MouseDown -= EditBox_LostFocus;
|
}
|
else
|
{
|
var win = sender as Window;
|
if (!GetElementUnderMouse(win, this))
|
{
|
//editing.Focu
|
IsEditing = false;
|
win.MouseDown -= EditBox_LostFocus;
|
Window.GetWindow(this).MouseDown -= EditBox_LostFocus;
|
}
|
}
|
Submited?.Invoke(this, null, null);
|
}
|
|
[Bindable(true)]
|
[Category("Appearance")]
|
public object Value
|
{
|
get { return GetValue(ValueProperty); }
|
set { SetValue(ValueProperty, value); }
|
}
|
|
public bool CanEdit
|
{
|
get => (bool)GetValue(CanEditProperty);
|
set
|
{
|
SetValue(CanEditProperty, value);
|
}
|
}
|
|
public bool IsEditing
|
{
|
get => (bool)GetValue(IsEditingProperty);
|
set
|
{
|
SetValue(IsEditingProperty, value);
|
}
|
}
|
|
public Func<bool?> PreEditing
|
{
|
get => (Func<bool?>)GetValue(PreEditingProperty);
|
set
|
{
|
SetValue(PreEditingProperty, value);
|
}
|
}
|
|
public Func<object,object,bool> PreSubmit
|
{
|
get => (Func<object, object, bool>)GetValue(PreSubmitProperty);
|
set
|
{
|
SetValue(PreSubmitProperty, value);
|
}
|
}
|
|
public Action<EditBox, object, object> Submited
|
{
|
get => (Action<EditBox, object, object>)GetValue(SubmitedProperty);
|
set
|
{
|
SetValue(SubmitedProperty, value);
|
}
|
}
|
|
public bool ShowEmpty
|
{
|
get => (bool)GetValue(ShowEmptyProperty);
|
set
|
{
|
SetValue(ShowEmptyProperty, value);
|
}
|
}
|
}
|
}
|