using System;
|
using System.Collections.Generic;
|
using System.ComponentModel;
|
using System.Globalization;
|
using System.Linq;
|
using System.Reflection;
|
using System.Windows;
|
using System.Windows.Controls;
|
using System.Windows.Data;
|
using System.Windows.Input;
|
|
namespace HMI.UI
|
{
|
public class MultiComboBoxItem : ComboBoxItem, INotifyPropertyChanged
|
{
|
#region ...
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
protected void RaisePropertyChanged(string propertyName)
|
{
|
if (PropertyChanged != null)
|
{
|
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
}
|
}
|
#endregion
|
|
private MultiComboBox parent;
|
public MultiComboBoxItem(MultiComboBox parent)
|
{
|
this.parent = parent;
|
this.DataContextChanged += MultiComboBoxItem_DataContextChanged;
|
}
|
|
protected override void OnMouseMove(MouseEventArgs e)
|
{
|
this.PreviewMouseUp += MultiComboBoxItem_PreviewMouseUp;
|
base.OnMouseMove(e);
|
}
|
|
protected override void OnMouseLeave(MouseEventArgs e)
|
{
|
this.PreviewMouseUp -= MultiComboBoxItem_PreviewMouseUp;
|
base.OnMouseLeave(e);
|
}
|
|
protected override void OnLostFocus(RoutedEventArgs e)
|
{
|
this.PreviewMouseUp -= MultiComboBoxItem_PreviewMouseUp;
|
base.OnLostFocus(e);
|
}
|
|
private void MultiComboBoxItem_PreviewMouseUp(object sender, MouseButtonEventArgs e)
|
{
|
if (e.OriginalSource is CheckBox)
|
{
|
// 从CheckBox点击传过来的事件要拉回焦点,不然会卡在Popup层当前的Item上
|
this.Focus();
|
}
|
if (DataContext is MultiComboBoxData data)
|
{
|
data.IsChecked = !data.IsChecked;
|
e.Handled = true;
|
}
|
}
|
|
private void MultiComboBoxItem_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
{
|
if (e.OldValue != null && e.OldValue is MultiComboBoxData oldData)
|
{
|
oldData.IsCheckedChanged -= DataIsCheckedChangedChange;
|
}
|
if (DataContext != null && DataContext is MultiComboBoxData newData)
|
{
|
newData.IsCheckedChanged += DataIsCheckedChangedChange;
|
}
|
}
|
|
private void DataIsCheckedChangedChange(object sender, bool isChecked)
|
{
|
parent.Item_IsCheckedChanged((MultiComboBoxData)sender, this, isChecked);
|
}
|
}
|
|
public class MultiComboBoxDataConverter : IValueConverter
|
{
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
{
|
if (value is IEnumerable<object> items)
|
{
|
return items.Select(item => new MultiComboBoxData(item, "DisplayName", "DataValue")).ToList();
|
}
|
return null;
|
}
|
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
{
|
return value;
|
}
|
}
|
|
public class MultiComboBoxData : INotifyPropertyChanged
|
{
|
#region ...
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
protected void RaisePropertyChanged(string propertyName)
|
{
|
if (PropertyChanged != null)
|
{
|
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
}
|
}
|
#endregion
|
|
public event EventHandler<bool> IsCheckedChanged;
|
|
private bool isChecked;
|
|
public bool IsChecked
|
{
|
get { return isChecked; }
|
set
|
{
|
isChecked = value;
|
RaisePropertyChanged("IsChecked");
|
IsCheckedChanged?.Invoke(this, value);
|
}
|
}
|
public string DisplayName
|
{
|
get => showName?.GetValue(Data).ToString();
|
}
|
|
public string DataValue
|
{
|
get => valueName?.GetValue(Data).ToString();
|
}
|
|
private PropertyInfo showName;
|
private PropertyInfo valueName;
|
|
public MultiComboBoxData(object data, string showName, string valueName)
|
{
|
this.Data = data;
|
this.showName = data.GetType().GetProperty(showName);
|
this.valueName = data.GetType().GetProperty(valueName);
|
}
|
|
public object Data { get; private set; }
|
}
|
|
/// <summary>
|
/// MultiCombox.xaml 的交互逻辑
|
/// </summary>
|
public partial class MultiComboBox : ComboBox
|
{
|
public static readonly string[] splits = new string[] { ", " };
|
|
protected override DependencyObject GetContainerForItemOverride()
|
{
|
var item = new MultiComboBoxItem(this);
|
return item;
|
}
|
|
[Bindable(true)]
|
[Category("Appearance")]
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
[Localizability(LocalizationCategory.NeverLocalize)]
|
public object SelectedValues
|
{
|
get
|
{
|
return GetValue(SelectedValuesProperty);
|
}
|
set
|
{
|
SetValue(SelectedValuesProperty, value);
|
}
|
}
|
|
public static readonly DependencyProperty SelectedValuesProperty =
|
DependencyProperty.RegisterAttached("SelectedValues", typeof(object), typeof(MultiComboBox),
|
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
|
|
public void Item_IsCheckedChanged(MultiComboBoxData data, MultiComboBoxItem item, bool isChecked)
|
{
|
var selectedValues = SelectedValues?.ToString() ?? "";
|
var showNames = this.Text?.ToString() ?? "";
|
List<string> values = string.IsNullOrEmpty(selectedValues) ? new List<string>() :
|
selectedValues.Split(splits, StringSplitOptions.RemoveEmptyEntries).ToList();
|
List<string> names = string.IsNullOrEmpty(showNames) ? new List<string>() :
|
showNames.Split(splits, StringSplitOptions.RemoveEmptyEntries).ToList();
|
if (isChecked)
|
{
|
values.Add(data.DataValue);
|
names.Add(data.DisplayName);
|
}
|
else
|
{
|
values.Remove(data.DataValue);
|
names.Remove(data.DisplayName);
|
}
|
Text = string.Join(", ", names);
|
SelectedValues = string.Join(", ", values);
|
}
|
}
|
}
|