using HMI.UI.Converter; using HMI.UI.MDI; using System; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; namespace HMI.UI { public class TableComboBox : ItemsControl { static TableComboBox() { DefaultStyleKeyProperty.OverrideMetadata(typeof(TableComboBox), new FrameworkPropertyMetadata(typeof(TableComboBox))); } public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value", typeof(object), typeof(TableComboBox), new FrameworkPropertyMetadata()); public static readonly DependencyProperty CanEditProperty = DependencyProperty.Register( "CanEdit", typeof(bool), typeof(TableComboBox), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnCanEditPropertyChanged))); public static DependencyProperty IsEditingProperty = DependencyProperty.Register( "IsEditing", typeof(bool), typeof(TableComboBox), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsEditingPropertyChanged))); public static DependencyProperty PreEditingProperty = DependencyProperty.Register( "PreEditing", typeof(Func), typeof(TableComboBox), new FrameworkPropertyMetadata()); public static DependencyProperty ShowEmptyProperty = DependencyProperty.Register( "ShowEmpty", typeof(bool), typeof(TableComboBox), new FrameworkPropertyMetadata(false)); public static DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register( "IsDropDownOpen", typeof(bool), typeof(TableComboBox), new FrameworkPropertyMetadata(false)); private static void OnCanEditPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { if (obj is TableComboBox 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 TableComboBox eb && e.Property == IsEditingProperty) { bool value = (bool)e.NewValue; eb.editor.Visibility = value ? Visibility.Visible : Visibility.Collapsed; if (value) { eb.editor.Focus(); } } } private ComboBox editor; public TableComboBox() { this.Loaded += EditBox_Loaded; } public bool IsDropDownOpen { get => (bool)GetValue(IsDropDownOpenProperty); set { SetValue(IsDropDownOpenProperty, value); } } private void EditBox_Loaded(object sender, RoutedEventArgs e) { editor = this.Template.FindName("PART_ComboBoxPart", this) as ComboBox; editor.DisplayMemberPath = this.DisplayMemberPath; editor.SelectedValuePath = this.SelectedValuePath; editor.ItemsSource = this.ItemsSource; editor.SelectedValue = Value; editor.SelectionChanged += Editor_SelectionChanged; Binding binding = new Binding("IsDropDownOpen") { Source = this, Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }; editor.SetBinding(ComboBox.IsDropDownOpenProperty, binding); } private void Editor_SelectionChanged(object sender, SelectionChangedEventArgs e) { ComboBox box = sender as ComboBox; if (IsEditing) { box.Focus(); } } 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; editor.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 (IsDropDownOpen) { return; } if (sender == editor) { IsEditing = false; editor.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; } } } public object Value { get { return GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } public bool CanEdit { get => (bool)GetValue(CanEditProperty); set { SetValue(CanEditProperty, value); } } public string SelectedValuePath { get; set; } 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); } } } }