using System;
|
using System.ComponentModel;
|
using System.Globalization;
|
using System.Windows;
|
using System.Windows.Controls;
|
using System.Windows.Data;
|
using System.Windows.Input;
|
using System.Windows.Media;
|
|
namespace UILib
|
{
|
public enum EditBoxType
|
{
|
String = 0,
|
Bool = 1
|
}
|
|
public class RelayCommand : ICommand
|
{
|
private readonly Action _execute;
|
private readonly Func<bool> _canExecute;
|
|
public RelayCommand(Action execute, Func<bool> canExecute = null)
|
{
|
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
|
_canExecute = canExecute;
|
}
|
|
public event EventHandler CanExecuteChanged
|
{
|
add => CommandManager.RequerySuggested += value;
|
remove => CommandManager.RequerySuggested -= value;
|
}
|
|
public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;
|
|
public void Execute(object parameter) => _execute();
|
}
|
|
public class EditBoxConverter : IMultiValueConverter
|
{
|
public static EditBoxConverter Instance = new EditBoxConverter();
|
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
{
|
if (values[0] is EditBox eb)
|
{
|
if (parameter?.ToString() == "StringFormat")
|
{
|
return eb.EditType == EditBoxType.String && eb.FormatString ? $"\"{values[1]}\"" : values[1]?.ToString();
|
}
|
if (parameter?.ToString() == "BoolIndex")
|
{
|
if (values[1] == null) return null;
|
return string.Equals("true", values[1]?.ToString(), StringComparison.OrdinalIgnoreCase) ? 0 : 1;
|
}
|
}
|
return null;
|
}
|
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
{
|
return null;
|
}
|
}
|
|
public class EditBox : Control
|
{
|
static EditBox()
|
{
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(EditBox), new FrameworkPropertyMetadata(typeof(EditBox)));
|
}
|
|
public static readonly DependencyProperty EditTypeProperty = DependencyProperty.Register(
|
"EditType",
|
typeof(EditBoxType),
|
typeof(EditBox), new PropertyMetadata(EditBoxType.String));
|
|
public static readonly DependencyProperty FormatStringProperty = DependencyProperty.Register(
|
"FormatString",
|
typeof(bool),
|
typeof(EditBox), new PropertyMetadata(false));
|
|
public static readonly DependencyProperty InitEditProperty = DependencyProperty.Register(
|
"InitEdit",
|
typeof(bool),
|
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<EditBox,bool>),
|
typeof(EditBox),
|
new FrameworkPropertyMetadata());
|
|
public static DependencyProperty PreSubmitProperty = DependencyProperty.Register(
|
"PreSubmit",
|
typeof(Func<object, 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.PreviewMouseDoubleClick += eb.EditBox_MouseDoubleClick;
|
//}
|
//else
|
//{
|
// eb.PreviewMouseDoubleClick -= eb.EditBox_MouseDoubleClick;
|
//}
|
}
|
}
|
|
private static void OnIsEditingPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
|
{
|
if (obj is EditBox eb && e.Property == IsEditingProperty)
|
{
|
bool value = (bool)e.NewValue;
|
|
if (eb.EditType == EditBoxType.String)
|
{
|
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;
|
}
|
}
|
else if (eb.EditType == EditBoxType.Bool)
|
{
|
|
eb.editingComboBox.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
|
if (value)
|
{
|
eb.editingComboBox.Focus();
|
eb.editingComboBox.IsDropDownOpen = true;
|
eb.editingComboBox.KeyDown += eb.EditBox_KeyDown;
|
}
|
else
|
{
|
eb.editingComboBox.KeyDown -= eb.EditBox_KeyDown;
|
}
|
}
|
}
|
}
|
|
private static void OnInitEditPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
|
{
|
if (obj is EditBox eb && e.Property == InitEditProperty)
|
{
|
bool value = (bool)e.NewValue;
|
if (eb.editing != null || !value)
|
{
|
return;
|
}
|
if (value)
|
{
|
|
}
|
}
|
}
|
|
public bool FormatString
|
{
|
get => (bool)GetValue(FormatStringProperty);
|
set
|
{
|
SetValue(FormatStringProperty, value);
|
}
|
}
|
|
public EditBoxType EditType
|
{
|
get => (EditBoxType)GetValue(EditTypeProperty);
|
set
|
{
|
SetValue(EditTypeProperty, value);
|
}
|
}
|
public TextBox editing { get; private set; }
|
private ComboBox editingComboBox;
|
public EditBox()
|
{
|
this.MouseDoubleClick += EditBox_MouseDoubleClick;
|
//if (CanEdit)
|
//{
|
|
//}
|
this.InputBindings.Add(new KeyBinding(
|
new RelayCommand(() => TryEdit(null)),
|
Key.F2,
|
ModifierKeys.None
|
));
|
this.Loaded += EditBox_Loaded;
|
}
|
|
private void EditBox_Loaded(object sender, RoutedEventArgs e)
|
{
|
//var control = this.Template.FindName("PART_TextBoxPart", this) as ContentControl;
|
//editing = control.Content as FrameworkElement;
|
if (EditType == EditBoxType.String)
|
{
|
editing = this.Template.FindName("PART_TextBoxPart", this) as TextBox;
|
}
|
else
|
{
|
editingComboBox = this.Template.FindName("PART_ComboBoxPart", this) as ComboBox;
|
}
|
//editing = control.Content as FrameworkElement;
|
}
|
|
private void EditBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
{
|
TryEdit(e);
|
}
|
|
public void TryEdit(MouseButtonEventArgs e)
|
{
|
if (!CanEdit)
|
{
|
return;
|
}
|
|
if (IsEditing)
|
{
|
return;
|
}
|
|
Func<EditBox, bool> pre = GetValue(PreEditingProperty) as Func<EditBox,bool>;
|
if (pre != null && pre.Invoke(this) != true)
|
{
|
return;
|
}
|
var win = Window.GetWindow(this);
|
|
win.MouseDown += Win_MouseDown;
|
if (EditType == EditBoxType.String)
|
{
|
editing.Focus();
|
//editing.LostFocus += TextBox_LostFocus;
|
this.LostFocus += EditBox_LostFocus;
|
}
|
else
|
{
|
editingComboBox.DropDownClosed += EditingComboBox_DropDownClosed;
|
}
|
IsEditing = true;
|
if (e != null)
|
{
|
e.Handled = true;
|
}
|
}
|
|
private void EditingComboBox_DropDownClosed(object sender, EventArgs e)
|
{
|
CancelEditing(sender);
|
}
|
|
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 TextBox_LostFocus(object sender, RoutedEventArgs e)
|
{
|
CancelEditing(sender);
|
}
|
|
private void Win_MouseDown(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 (EditType == EditBoxType.String)
|
{
|
if (PreSubmit != null && !PreSubmit.Invoke(this, editing.Text, DataContext))
|
{
|
editing.Text = Value?.ToString();
|
|
Dispatcher.BeginInvoke(new Action(() =>
|
{
|
editing.Focus();
|
}), System.Windows.Threading.DispatcherPriority.Input);
|
//editing.LostFocus += TextBox_LostFocus;
|
return;
|
}
|
}
|
|
if (EditType == EditBoxType.String)
|
{
|
IsEditing = false;
|
this.LostFocus -= EditBox_LostFocus;
|
editing.LostFocus -= TextBox_LostFocus;
|
Window.GetWindow(this).MouseDown -= Win_MouseDown;
|
}
|
else if (EditType == EditBoxType.Bool)
|
{
|
IsEditing = false;
|
editingComboBox.DropDownClosed -= EditingComboBox_DropDownClosed;
|
Window.GetWindow(this).MouseDown -= Win_MouseDown;
|
}
|
else
|
{
|
var win = sender as Window;
|
if (!GetElementUnderMouse(win, this))
|
{
|
//editing.Focu
|
IsEditing = false;
|
win.MouseDown -= Win_MouseDown;
|
Window.GetWindow(this).MouseDown -= Win_MouseDown;
|
}
|
}
|
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<EditBox, bool> PreEditing
|
{
|
get => (Func<EditBox, bool>)GetValue(PreEditingProperty);
|
set
|
{
|
SetValue(PreEditingProperty, value);
|
}
|
}
|
|
public Func<object, object, object, bool> PreSubmit
|
{
|
get => (Func<object, 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);
|
}
|
}
|
|
public bool InitEdit
|
{
|
get => (bool)GetValue(InitEditProperty);
|
set
|
{
|
SetValue(InitEditProperty, value);
|
}
|
}
|
}
|
}
|