using System; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace HMI.UI { 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(false, 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 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(); } } } private TextBox editing; public EditBox() { 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) { 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; } } } [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 bool ShowEmpty { get => (bool)GetValue(ShowEmptyProperty); set { SetValue(ShowEmptyProperty, value); } } } }