204 lines
6.4 KiB
C#
204 lines
6.4 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Linq;
|
|
using System.Windows.Controls;
|
|
|
|
|
|
namespace WPFluent.Controls;
|
|
|
|
/// <summary>
|
|
/// 多选树形视图控件。
|
|
/// </summary>
|
|
public sealed class MultiTreeView : System.Windows.Controls.TreeView
|
|
{
|
|
public static readonly DependencyProperty SelectedItemsProperty =
|
|
DependencyProperty.Register(
|
|
nameof(SelectedItems),
|
|
typeof(IList),
|
|
typeof(MultiTreeView),
|
|
new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedItemsChanged)));
|
|
|
|
static MultiTreeView()
|
|
{
|
|
DefaultStyleKeyProperty.OverrideMetadata(
|
|
typeof(MultiTreeView),
|
|
new FrameworkPropertyMetadata(typeof(MultiTreeView)));
|
|
}
|
|
|
|
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
var list = e.NewValue as IList;
|
|
//foreach (var item in list)
|
|
//{
|
|
|
|
//}
|
|
}
|
|
|
|
// public static readonly DependencyPropertyKey SelectedItemsPropertyKey =
|
|
// DependencyProperty.RegisterReadOnly(
|
|
//nameof(SelectedItems),
|
|
// typeof(IList),
|
|
// typeof(MultiTreeViewItem),
|
|
// new FrameworkPropertyMetadata(null)
|
|
// );
|
|
|
|
// public static readonly DependencyProperty SelectedItemsProperty = SelectedItemsPropertyKey.DependencyProperty;
|
|
|
|
// public IList SelectedItems
|
|
// {
|
|
// get { return (IList)GetValue(SelectedItemsProperty); }
|
|
// private set { SetValue(SelectedItemsPropertyKey, value); }
|
|
// }
|
|
public IList SelectedItems
|
|
{
|
|
get { return (IList)GetValue(SelectedItemsProperty); }
|
|
set { SetValue(SelectedItemsProperty, value); }
|
|
}
|
|
|
|
#region Event Handlers
|
|
|
|
/// <summary>
|
|
/// 在鼠标按下事件发生时调用。
|
|
/// </summary>
|
|
//protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
|
|
//{
|
|
// base.OnPreviewMouseDown(e);
|
|
|
|
// //// 如果点击树分支expander
|
|
// //if (e.OriginalSource is Grid or Border or TextBlock)
|
|
// // return;
|
|
// var obj = e.OriginalSource as DependencyObject;
|
|
|
|
// var checkBox = obj.FindParent<CheckBox>();
|
|
|
|
// if (checkBox != null)
|
|
// {
|
|
// //当前点击的MultiTreeViewItem
|
|
// var currentItem = GetTreeViewItemClicked((FrameworkElement)e.OriginalSource);
|
|
|
|
// if (currentItem != null)
|
|
// {
|
|
// SelectedItems = GetTreeViewItems(this, true).Where(d => d.IsChecked == true).ToList();
|
|
// }
|
|
// }
|
|
//}
|
|
#endregion Event Handlers
|
|
#region Utility Methods
|
|
|
|
#region 重写
|
|
|
|
///// <summary>
|
|
///// 准备项的容器
|
|
///// </summary>
|
|
///// <param name="element">控件元素</param>
|
|
///// <param name="item">绑定的对象</param>
|
|
//protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
|
|
//{
|
|
// if (item is not MultiTreeViewItem)
|
|
// {
|
|
// if (element is MultiTreeViewItem multiTreeViewItem && !string.IsNullOrEmpty(this.DisplayMemberPath))
|
|
// {
|
|
// var binding = new Binding(this.DisplayMemberPath);
|
|
// multiTreeViewItem.SetBinding(MultiTreeViewItem.HeaderProperty, binding);
|
|
// }
|
|
// }
|
|
// base.PrepareContainerForItemOverride(element, item);
|
|
//}
|
|
|
|
/// <summary>
|
|
/// 获取项的容器。
|
|
/// </summary>
|
|
protected override DependencyObject GetContainerForItemOverride() { return new MultiTreeViewItem(); }
|
|
|
|
/// <summary>
|
|
/// 确定项是否是其自己的容器。
|
|
/// </summary>
|
|
protected override bool IsItemItsOwnContainerOverride(object item)
|
|
{
|
|
return item is MultiTreeViewItem;
|
|
}
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// 获取当前被点击的MultiTreeViewItem。
|
|
/// </summary>
|
|
private static MultiTreeViewItem? GetTreeViewItemClicked(DependencyObject sender)
|
|
{
|
|
while(sender is not null and not MultiTreeViewItem)
|
|
sender = VisualTreeHelper.GetParent(sender);
|
|
return sender as MultiTreeViewItem;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取树形视图的所有展开的项。
|
|
/// </summary>
|
|
private List<MultiTreeViewItem> GetTreeViewItems(
|
|
ItemsControl parentItem,
|
|
bool includeCollapsedItems,
|
|
List<MultiTreeViewItem>? itemList = null)
|
|
{
|
|
itemList ??= [];
|
|
|
|
for(var index = 0; index < parentItem.Items.Count; index++)
|
|
{
|
|
if(parentItem.ItemContainerGenerator.ContainerFromIndex(index) is not MultiTreeViewItem tvItem)
|
|
{
|
|
continue;
|
|
}
|
|
itemList.Add(tvItem);
|
|
if(includeCollapsedItems || tvItem.IsExpanded)
|
|
{
|
|
GetTreeViewItems(tvItem, includeCollapsedItems, itemList);
|
|
}
|
|
}
|
|
return itemList;
|
|
}
|
|
|
|
internal void NotifyMultiTreeViewItemClicked(MultiTreeViewItem multiTreeViewItem)
|
|
{
|
|
var selectedItems = GetTreeViewItems(this, true).Where(d => d.IsChecked == true);
|
|
if(ItemsSource == null)
|
|
{
|
|
SelectedItems = selectedItems.ToList();
|
|
}
|
|
else
|
|
{
|
|
//选择绑定的对象
|
|
SelectedItems = selectedItems.Select(d => d.DataContext).ToList();
|
|
}
|
|
}
|
|
|
|
///// <summary>
|
|
///// 获取两个树形视图项之间的所有项。
|
|
///// </summary>
|
|
//private List<MultiTreeViewItem> GetTreeViewItemRange(MultiTreeViewItem start, MultiTreeViewItem end)
|
|
//{
|
|
// var items = GetTreeViewItems(this, false);
|
|
// var startIndex = items.IndexOf(start);
|
|
// var endIndex = items.IndexOf(end);
|
|
// var rangeStart = startIndex > endIndex || startIndex == -1 ? endIndex : startIndex;
|
|
// var rangeCount = startIndex > endIndex ? startIndex - endIndex + 1 : endIndex - startIndex + 1;
|
|
|
|
// if (startIndex == -1 && endIndex == -1)
|
|
// rangeCount = 0;
|
|
|
|
// else if (startIndex == -1 || endIndex == -1)
|
|
// rangeCount = 1;
|
|
|
|
// return rangeCount > 0 ? items.GetRange(rangeStart, rangeCount) : new List<MultiTreeViewItem>();
|
|
//}
|
|
#endregion Utility Methods
|
|
|
|
/// <summary>
|
|
/// 初始化 MultiTreeView 类的新实例。
|
|
/// </summary>
|
|
//public MultiTreeView()
|
|
//{
|
|
//SelectedItemChanged += (sender, e) =>
|
|
//{
|
|
// if (e.NewValue is MultiTreeViewItem item)
|
|
// SelectedItemChangedInternal(item);
|
|
//};
|
|
//}
|
|
}
|