156 lines
5.1 KiB
C#
156 lines
5.1 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Collections.ObjectModel;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
using System.Windows;
|
|||
|
|
using System.Windows.Controls;
|
|||
|
|
using System.Windows.Input;
|
|||
|
|
|
|||
|
|
namespace Wpf.Ui.Extend.Controls;
|
|||
|
|
public class TreeComboBox : ComboBox
|
|||
|
|
{
|
|||
|
|
public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(IEnumerable), typeof(TreeComboBox), new PropertyMetadata(null));
|
|||
|
|
public static readonly DependencyProperty ParentPathProperty = DependencyProperty.Register("ParentPath", typeof(string), typeof(TreeComboBox), new PropertyMetadata());
|
|||
|
|
public static readonly DependencyProperty SelectedNodeProperty = DependencyProperty.Register("SelectedNode", typeof(object), typeof(TreeComboBox), new FrameworkPropertyMetadata(default));
|
|||
|
|
public static readonly DependencyProperty IsCheckedPathProperty = DependencyProperty.Register("IsCheckedPath", typeof(string), typeof(TreeComboBox), new PropertyMetadata());
|
|||
|
|
public static readonly DependencyProperty IsExpandedPathProperty = DependencyProperty.Register("IsExpandedPath", typeof(string), typeof(TreeComboBox), new PropertyMetadata("IsExpanded"));
|
|||
|
|
public static readonly DependencyProperty IsSelectedPathProperty = DependencyProperty.Register("IsSelectedPath", typeof(string), typeof(TreeComboBox), new PropertyMetadata("IsSelected"));
|
|||
|
|
|
|||
|
|
private ExtendedTreeView _treeView;
|
|||
|
|
private ObservableCollection<object> list = [];
|
|||
|
|
|
|||
|
|
static TreeComboBox()
|
|||
|
|
{
|
|||
|
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeComboBox), new FrameworkPropertyMetadata(typeof(TreeComboBox)));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
|||
|
|
{
|
|||
|
|
//don't call the method of the base class
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void OnApplyTemplate()
|
|||
|
|
{
|
|||
|
|
_treeView = (ExtendedTreeView)this.GetTemplateChild("treeView");
|
|||
|
|
_treeView.OnHierarchyMouseUp += new MouseEventHandler(OnTreeViewHierarchyMouseUp);
|
|||
|
|
_treeView.OnChecked += _treeView_OnChecked;
|
|||
|
|
this.UpdateSelectedItem();
|
|||
|
|
base.OnApplyTemplate();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void _treeView_OnChecked(object sender, RoutedEventArgs e)
|
|||
|
|
{
|
|||
|
|
if (sender is CheckableTreeViewItem { IsChecked: bool isChecked } item)
|
|||
|
|
{
|
|||
|
|
if (isChecked)
|
|||
|
|
{
|
|||
|
|
list.Add(item.DataContext);
|
|||
|
|
}
|
|||
|
|
else if (list.Contains(item))
|
|||
|
|
{
|
|||
|
|
list.Remove(item.DataContext);
|
|||
|
|
}
|
|||
|
|
SelectedItems = list;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void OnDropDownClosed(EventArgs e)
|
|||
|
|
{
|
|||
|
|
base.OnDropDownClosed(e);
|
|||
|
|
this.UpdateSelectedItem();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void OnDropDownOpened(EventArgs e)
|
|||
|
|
{
|
|||
|
|
base.OnDropDownOpened(e);
|
|||
|
|
this.UpdateSelectedItem();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Handles clicks on any item in the tree view
|
|||
|
|
/// </summary>
|
|||
|
|
private void OnTreeViewHierarchyMouseUp(object sender, MouseEventArgs e)
|
|||
|
|
{
|
|||
|
|
var hierarchy = SelectItems();
|
|||
|
|
this.SelectedItem = hierarchy.First();
|
|||
|
|
this.SelectedItems = hierarchy;
|
|||
|
|
UpdateSelectedItem();
|
|||
|
|
this.IsDropDownOpen = false;
|
|||
|
|
this.SelectedNode = _treeView.SelectedItem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#region properties
|
|||
|
|
|
|||
|
|
public string IsExpandedPath
|
|||
|
|
{
|
|||
|
|
get { return (string)GetValue(IsExpandedPathProperty); }
|
|||
|
|
set { SetValue(IsExpandedPathProperty, value); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public string IsSelectedPath
|
|||
|
|
{
|
|||
|
|
get { return (string)GetValue(IsSelectedPathProperty); }
|
|||
|
|
set { SetValue(IsSelectedPathProperty, value); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public string IsCheckedPath
|
|||
|
|
{
|
|||
|
|
get { return (string)GetValue(IsCheckedPathProperty); }
|
|||
|
|
set { SetValue(IsCheckedPathProperty, value); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public string ParentPath
|
|||
|
|
{
|
|||
|
|
get { return (string)GetValue(ParentPathProperty); }
|
|||
|
|
set { SetValue(ParentPathProperty, value); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public object SelectedNode
|
|||
|
|
{
|
|||
|
|
get { return GetValue(SelectedNodeProperty); }
|
|||
|
|
set { SetValue(SelectedNodeProperty, value); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public IEnumerable SelectedItems
|
|||
|
|
{
|
|||
|
|
get { return (IEnumerable)GetValue(SelectedItemsProperty); }
|
|||
|
|
set { SetValue(SelectedItemsProperty, value); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
#endregion properties
|
|||
|
|
|
|||
|
|
private void UpdateSelectedItem()
|
|||
|
|
{
|
|||
|
|
if (_treeView.SelectedItem != null)
|
|||
|
|
{
|
|||
|
|
var hierarchy = SelectItems();
|
|||
|
|
SelectedItems = hierarchy;
|
|||
|
|
SelectedNode = hierarchy.Last();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private object[] SelectItems()
|
|||
|
|
{
|
|||
|
|
var type = _treeView.SelectedItem.GetType();
|
|||
|
|
var propInfo = type.GetProperty(ParentPath);
|
|||
|
|
return TreeHelper.GetAncestors(_treeView.SelectedItem, a => propInfo.GetValue(a)).Reverse().ToArray();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static class TreeHelper
|
|||
|
|
{
|
|||
|
|
public static IEnumerable<object> GetAncestors(object vm, Func<object, object> parent)
|
|||
|
|
{
|
|||
|
|
yield return vm;
|
|||
|
|
while (parent(vm) != null)
|
|||
|
|
{
|
|||
|
|
yield return parent(vm);
|
|||
|
|
vm = parent(vm);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|