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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|