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), typeof(EditBox), new FrameworkPropertyMetadata()); public static DependencyProperty PreSubmitProperty = DependencyProperty.Register( "PreSubmit", typeof(Func), typeof(EditBox), new FrameworkPropertyMetadata()); public static DependencyProperty SubmitedProperty = DependencyProperty.Register( "Submited", typeof(Action), 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 pre = GetValue(PreEditingProperty) as Func; 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 PreEditing { get => (Func)GetValue(PreEditingProperty); set { SetValue(PreEditingProperty, value); } } public Func PreSubmit { get => (Func)GetValue(PreSubmitProperty); set { SetValue(PreSubmitProperty, value); } } public Action Submited { get => (Action)GetValue(SubmitedProperty); set { SetValue(SubmitedProperty, value); } } public bool ShowEmpty { get => (bool)GetValue(ShowEmptyProperty); set { SetValue(ShowEmptyProperty, value); } } } }