2025-02-10 20:53:40 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
using System;
|
2025-05-05 17:04:06 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
|
using System.Windows.Controls.Primitives;
|
|
|
|
|
|
using System.Windows.Data;
|
|
|
|
|
|
|
2025-05-05 17:04:06 +08:00
|
|
|
|
using WPFluent.Extensions;
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2025-02-10 20:53:40 +08:00
|
|
|
|
namespace WPFluent.Controls
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 通过该类,对绑定的集合->重新创建为CheckComboBoxItem->应用默认样式
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class CheckComboBox : ComboBoxEx
|
|
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
#region Internal
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 行选中
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="item"></param>
|
|
|
|
|
|
internal void NotifyCheckComboBoxItemClicked(CheckComboBoxItem item)
|
|
|
|
|
|
{
|
|
|
|
|
|
var itemContent = Convert.ToString(item.Content);
|
|
|
|
|
|
SelectedStrList ??= [];
|
|
|
|
|
|
SelectedObjList ??= [];
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (item.IsSelected)
|
2025-02-10 20:53:40 +08:00
|
|
|
|
{
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (!SelectedStrList.Contains(item.Content))
|
2025-02-10 20:53:40 +08:00
|
|
|
|
{
|
|
|
|
|
|
SelectedStrList.Add(itemContent);
|
|
|
|
|
|
}
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (!SelectedObjList.Contains(item.DataContext))
|
2025-02-10 20:53:40 +08:00
|
|
|
|
{
|
|
|
|
|
|
SelectedObjList.Add(item.DataContext);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (SelectedStrList.Contains(itemContent))
|
2025-02-10 20:53:40 +08:00
|
|
|
|
{
|
|
|
|
|
|
SelectedStrList.Remove(itemContent);
|
|
|
|
|
|
}
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (SelectedObjList.Contains(item.DataContext))
|
2025-02-10 20:53:40 +08:00
|
|
|
|
{
|
|
|
|
|
|
SelectedObjList.Remove(item.DataContext);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
SetCheckComboBoxValueAndContent();
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
#region PrivateProperty
|
|
|
|
|
|
private ContentPresenter PART_ContentSite;
|
2025-05-05 17:04:06 +08:00
|
|
|
|
private System.Windows.Controls.TextBox PART_FilterTextBox;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
private ICollectionView view;
|
|
|
|
|
|
private Popup PART_Popup;
|
|
|
|
|
|
|
|
|
|
|
|
private bool popupIsFirstOpen;
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region DependencyProperty
|
|
|
|
|
|
public static readonly DependencyProperty ContentProperty =
|
2025-02-10 20:53:40 +08:00
|
|
|
|
DependencyProperty.Register(
|
|
|
|
|
|
nameof(Content),
|
|
|
|
|
|
typeof(string),
|
|
|
|
|
|
typeof(CheckComboBox),
|
|
|
|
|
|
new PropertyMetadata(string.Empty));
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 内容
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public string Content
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (string)GetValue(ContentProperty); }
|
|
|
|
|
|
set { SetValue(ContentProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty ValueProperty =
|
2025-02-10 20:53:40 +08:00
|
|
|
|
DependencyProperty.Register(
|
|
|
|
|
|
nameof(Value),
|
|
|
|
|
|
typeof(string),
|
|
|
|
|
|
typeof(CheckComboBox),
|
|
|
|
|
|
new PropertyMetadata(string.Empty));
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 值
|
|
|
|
|
|
/// </summary>
|
2025-02-10 20:53:40 +08:00
|
|
|
|
public string Value { get { return (string)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } }
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
#region SelectedObjList
|
|
|
|
|
|
[Bindable(true), Description("获取或者设置当前勾选项列表")]
|
|
|
|
|
|
public ObservableCollection<object> SelectedObjList
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (ObservableCollection<object>)GetValue(SelectedObjListProperty); }
|
|
|
|
|
|
set { SetValue(SelectedObjListProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty SelectedObjListProperty =
|
2025-02-10 20:53:40 +08:00
|
|
|
|
DependencyProperty.Register(
|
|
|
|
|
|
nameof(SelectedObjList),
|
|
|
|
|
|
typeof(ObservableCollection<object>),
|
|
|
|
|
|
typeof(CheckComboBox),
|
|
|
|
|
|
new PropertyMetadata(null, OnSelectedObjListChanged));
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
private static void OnSelectedObjListChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
var checkComboBox = d as CheckComboBox;
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (checkComboBox.ItemsSource != null)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
checkComboBox.SetCheckComboBoxValueAndContent();
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region SelectedStrList
|
|
|
|
|
|
public ObservableCollection<string> SelectedStrList
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (ObservableCollection<string>)GetValue(SelectedStrListProperty); }
|
|
|
|
|
|
set { SetValue(SelectedStrListProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty SelectedStrListProperty =
|
2025-02-10 20:53:40 +08:00
|
|
|
|
DependencyProperty.Register(
|
|
|
|
|
|
nameof(SelectedStrList),
|
|
|
|
|
|
typeof(ObservableCollection<string>),
|
|
|
|
|
|
typeof(CheckComboBox));
|
2024-09-22 11:05:41 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或者设置最多显示的选中个数
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int MaxShowNumber
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (int)GetValue(MaxShowNumberProperty); }
|
|
|
|
|
|
set { SetValue(MaxShowNumberProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty MaxShowNumberProperty =
|
2025-02-10 20:53:40 +08:00
|
|
|
|
DependencyProperty.Register(
|
|
|
|
|
|
nameof(MaxShowNumber),
|
|
|
|
|
|
typeof(int),
|
|
|
|
|
|
typeof(CheckComboBox),
|
|
|
|
|
|
new PropertyMetadata(3));
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Constructors
|
|
|
|
|
|
static CheckComboBox()
|
|
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
DefaultStyleKeyProperty.OverrideMetadata(
|
|
|
|
|
|
typeof(CheckComboBox),
|
|
|
|
|
|
new FrameworkPropertyMetadata(typeof(CheckComboBox)));
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
2025-02-10 20:53:40 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
public CheckComboBox()
|
|
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
SelectedObjList = [];
|
|
|
|
|
|
SelectedStrList = [];
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Override
|
|
|
|
|
|
public override void OnApplyTemplate()
|
|
|
|
|
|
{
|
|
|
|
|
|
base.OnApplyTemplate();
|
|
|
|
|
|
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (PART_FilterTextBox != null)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
PART_FilterTextBox.TextChanged -= PART_FilterTextBox_TextChanged;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (PART_Popup != null)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
PART_Popup.Opened -= PART_Popup_Opened;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-10 20:53:40 +08:00
|
|
|
|
PART_ContentSite = GetTemplateChild("PART_ContentSite") as ContentPresenter;
|
2025-05-05 17:04:06 +08:00
|
|
|
|
PART_FilterTextBox = GetTemplateChild("PART_FilterTextBox") as System.Windows.Controls.TextBox;
|
2025-02-10 20:53:40 +08:00
|
|
|
|
PART_Popup = GetTemplateChild("PART_Popup") as Popup;
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (PART_FilterTextBox != null)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
PART_FilterTextBox.TextChanged += PART_FilterTextBox_TextChanged;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
2025-02-10 20:53:40 +08:00
|
|
|
|
view = CollectionViewSource.GetDefaultView(ItemsSource);
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (PART_Popup != null)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
PART_Popup.Opened += PART_Popup_Opened;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
2025-02-10 20:53:40 +08:00
|
|
|
|
Init();
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
2025-02-10 20:53:40 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
|
|
|
|
|
|
{
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (item is not CheckComboBoxItem)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (element is CheckComboBoxItem checkComboBoxItem && !string.IsNullOrEmpty(DisplayMemberPath))
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
var binding = new Binding(DisplayMemberPath);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
checkComboBoxItem.SetBinding(CheckComboBoxItem.ContentProperty, binding);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
base.PrepareContainerForItemOverride(element, item);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-10 20:53:40 +08:00
|
|
|
|
protected override DependencyObject GetContainerForItemOverride() { return new CheckComboBoxItem(); }
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
protected override bool IsItemItsOwnContainerOverride(object item)
|
|
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
return item is CheckComboBoxItem;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region PrivateFunction
|
|
|
|
|
|
private void Init()
|
|
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
popupIsFirstOpen = true;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (SelectedObjList != null)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-05-05 17:04:06 +08:00
|
|
|
|
foreach (var obj in SelectedObjList)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (string.IsNullOrWhiteSpace(DisplayMemberPath))
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
SelectedStrList.Add(obj.ToString());
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
SelectedStrList.Add(obj.GetPropertyValue(DisplayMemberPath).ToString());
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-02-10 20:53:40 +08:00
|
|
|
|
SetCheckComboBoxValueAndContent();
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SetCheckComboBoxValueAndContent()
|
|
|
|
|
|
{
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (SelectedObjList == null || SelectedObjList.Count <= 0)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
SelectedStrList = [];
|
|
|
|
|
|
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (SelectedStrList == null)
|
2025-02-10 20:53:40 +08:00
|
|
|
|
return;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2025-02-10 20:53:40 +08:00
|
|
|
|
Content = SelectedStrList.Count > MaxShowNumber
|
|
|
|
|
|
? $"选中{SelectedStrList.Count}个"
|
|
|
|
|
|
: SelectedStrList.Aggregate(string.Empty, (current, p) => $"{current}{p}, ")
|
2025-07-11 09:20:23 +08:00
|
|
|
|
.TrimEnd([' '])
|
|
|
|
|
|
.TrimEnd([',']);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2025-02-10 20:53:40 +08:00
|
|
|
|
Value = SelectedStrList.Aggregate(string.Empty, (current, p) => $"{current}{p},")
|
2025-07-11 09:20:23 +08:00
|
|
|
|
.TrimEnd([',']);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Event Implement Function
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 每次Open回显数据不太好,先这么处理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void PART_Popup_Opened(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (!popupIsFirstOpen)
|
2025-02-10 20:53:40 +08:00
|
|
|
|
return;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2025-02-10 20:53:40 +08:00
|
|
|
|
popupIsFirstOpen = false;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (ItemsSource == null || SelectedObjList == null)
|
2025-02-10 20:53:40 +08:00
|
|
|
|
return;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2025-05-05 17:04:06 +08:00
|
|
|
|
foreach (var obj in SelectedObjList)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (ItemContainerGenerator.ContainerFromItem(obj) is CheckComboBoxItem checkComboBoxItem)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
checkComboBoxItem.IsSelected = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-02-10 20:53:40 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 搜索关键字
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void PART_FilterTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
|
|
|
|
|
{
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (PART_FilterTextBox == null || view == null)
|
2025-02-10 20:53:40 +08:00
|
|
|
|
return;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
view.Filter += (o) =>
|
|
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
var value = Convert.ToString(o.GetPropertyValue(DisplayMemberPath)).ToLower();
|
|
|
|
|
|
return value.Contains(PART_FilterTextBox.Text);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
};
|
2025-05-05 17:04:06 +08:00
|
|
|
|
foreach (var obj in SelectedObjList)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2025-05-05 17:04:06 +08:00
|
|
|
|
if (ItemContainerGenerator.ContainerFromItem(obj) is CheckComboBoxItem checkComboBoxItem)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
checkComboBoxItem.IsSelected = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|