142 lines
5.0 KiB
C#
142 lines
5.0 KiB
C#
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Controls.Primitives;
|
||
using System.Windows.Input;
|
||
using System.Windows.Media;
|
||
using PropertyMetadata = System.Windows.PropertyMetadata;
|
||
|
||
namespace YY.Admin.Core.Behavior
|
||
{
|
||
public class TreeViewItemClickBehavior
|
||
{
|
||
// ICommand attached property
|
||
public static readonly DependencyProperty CommandProperty =
|
||
DependencyProperty.RegisterAttached(
|
||
"Command",
|
||
typeof(ICommand),
|
||
typeof(TreeViewItemClickBehavior),
|
||
new PropertyMetadata(null, OnCommandChanged));
|
||
|
||
public static void SetCommand(DependencyObject obj, ICommand value) => obj.SetValue(CommandProperty, value);
|
||
public static ICommand GetCommand(DependencyObject obj) => (ICommand)obj.GetValue(CommandProperty);
|
||
|
||
// CommandParameter attached property
|
||
public static readonly DependencyProperty CommandParameterProperty =
|
||
DependencyProperty.RegisterAttached(
|
||
"CommandParameter",
|
||
typeof(object),
|
||
typeof(TreeViewItemClickBehavior),
|
||
new PropertyMetadata(null));
|
||
|
||
public static void SetCommandParameter(DependencyObject obj, object value) => obj.SetValue(CommandParameterProperty, value);
|
||
public static object GetCommandParameter(DependencyObject obj) => obj.GetValue(CommandParameterProperty);
|
||
|
||
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
{
|
||
if (d is TreeViewItem tvi)
|
||
{
|
||
if (e.NewValue != null && e.OldValue == null)
|
||
{
|
||
tvi.PreviewMouseLeftButtonUp += OnTreeViewItemMouseLeftButtonUp;
|
||
// 监听 TreeViewItem 展开事件Expanded
|
||
tvi.Expanded += OnTreeViewItemExpanded;
|
||
}
|
||
else if (e.NewValue == null && e.OldValue != null)
|
||
{
|
||
tvi.PreviewMouseLeftButtonUp -= OnTreeViewItemMouseLeftButtonUp;
|
||
tvi.Expanded -= OnTreeViewItemExpanded;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 如果Style被应用到容器等,也可能不是TreeViewItem,延迟订阅由容器化过程处理
|
||
// 一般我们只使用在 TreeViewItem 上设置
|
||
}
|
||
}
|
||
|
||
private static void OnTreeViewItemMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||
{
|
||
// 忽略点击展开按钮
|
||
if (e.OriginalSource is DependencyObject dep)
|
||
{
|
||
if (FindAncestor<ToggleButton>(dep) != null) return;
|
||
|
||
// 找到真正的 TreeViewItem
|
||
var tvi = FindAncestor<TreeViewItem>(dep);
|
||
if (tvi == null) return;
|
||
|
||
var cmd = GetCommand(tvi);
|
||
var param = GetCommandParameter(tvi) ?? tvi.DataContext;
|
||
|
||
// 检查是否有子项
|
||
bool hasChildren = tvi.HasItems;
|
||
|
||
// 如果有子项,则切换展开状态
|
||
if (hasChildren)
|
||
{
|
||
bool IsExpanded = !tvi.IsExpanded;
|
||
tvi.IsExpanded = IsExpanded;
|
||
|
||
// 展开
|
||
//if (IsExpanded)
|
||
//{
|
||
// // 关闭同级其它节点
|
||
// CollapseSiblings(tvi);
|
||
//}
|
||
|
||
e.Handled = true;
|
||
return;
|
||
}
|
||
|
||
if (cmd != null && cmd.CanExecute(param))
|
||
{
|
||
cmd.Execute(param);
|
||
e.Handled = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
private static void OnTreeViewItemExpanded(object sender, RoutedEventArgs e)
|
||
{
|
||
if (sender is TreeViewItem tvi)
|
||
{
|
||
// 防止事件冒泡重复执行
|
||
if (e.OriginalSource != tvi)
|
||
return;
|
||
|
||
CollapseSiblings(tvi);
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 折叠同级其它 TreeViewItem
|
||
/// </summary>
|
||
private static void CollapseSiblings(TreeViewItem currentItem)
|
||
{
|
||
ItemsControl parent = ItemsControl.ItemsControlFromItemContainer(currentItem);
|
||
if (parent == null) return;
|
||
|
||
foreach (var item in parent.Items)
|
||
{
|
||
var container = parent.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
|
||
if (container != null && container != currentItem)
|
||
{
|
||
container.IsExpanded = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 查找祖先辅助方法
|
||
private static T FindAncestor<T>(DependencyObject current) where T : DependencyObject
|
||
{
|
||
while (current != null)
|
||
{
|
||
if (current is T t) return t;
|
||
current = VisualTreeHelper.GetParent(current);
|
||
}
|
||
return null;
|
||
}
|
||
}
|
||
}
|