Add template generate items for tree

This commit is contained in:
chinboy
2025-10-21 12:27:21 +08:00
parent 9dc3c7f6b4
commit 41b28ed37e
8 changed files with 521 additions and 308 deletions
@@ -115,11 +115,11 @@ internal class DefaultTreeViewInteractionHandler : ITreeViewInteractionHandler
if (e.InitialPressMouseButton == MouseButton.Left && item != null)
{
// if (item.PointInHeaderBounds(e))
// {
// Click(item);
// e.Handled = true;
// }
if (item.PointInHeaderBounds(e))
{
Click(item);
e.Handled = true;
}
}
}
@@ -5,5 +5,6 @@ public interface ITreeViewItemData : ITreeNode<ITreeViewItemData>
bool? IsChecked { get; }
bool IsSelected { get; }
bool IsExpanded { get; }
bool IsIndicatorEnabled { get; }
string? GroupName { get; }
}
@@ -290,11 +290,7 @@ public partial class TreeView
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == DefaultCheckedPathsProperty)
{
ConfigureDefaultCheckedPaths();
}
else if (change.Property == DefaultSelectedPathsProperty)
if (change.Property == DefaultSelectedPathsProperty)
{
ConfigureDefaultSelectedPaths();
}
+344 -245
View File
@@ -14,7 +14,6 @@ using Avalonia.Controls.Metadata;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.VisualTree;
using DynamicData;
namespace AtomUI.Controls;
@@ -198,6 +197,21 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
#endregion
#region 公共事件定义
public static readonly RoutedEvent<TreeViewCheckedItemsChangedEventArgs> CheckedItemsChangedEvent =
RoutedEvent.Register<TreeView, TreeViewCheckedItemsChangedEventArgs>(
nameof(CheckedItemsChangedEvent),
RoutingStrategies.Bubble);
public event EventHandler<TreeViewCheckedItemsChangedEventArgs>? CheckedItemsChanged
{
add => AddHandler(CheckedItemsChangedEvent, value);
remove => RemoveHandler(CheckedItemsChangedEvent, value);
}
#endregion
#region 内部属性定义
internal static readonly StyledProperty<TimeSpan> MotionDurationProperty =
@@ -218,7 +232,7 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
#endregion
private readonly Dictionary<TreeViewItem, CompositeDisposable> _itemsBindingDisposables = new();
private static readonly IList<ITreeViewItemData> Empty = Array.Empty<ITreeViewItemData>();
private IList<ITreeViewItemData>? _checkedItems;
private bool _syncingCheckedItems;
@@ -235,7 +249,7 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
{
InteractionHandler = interactionHandler ?? throw new ArgumentNullException(nameof(interactionHandler));
this.RegisterResources();
Items.CollectionChanged += HandleCollectionChanged;
LogicalChildren.CollectionChanged += HandleCollectionChanged;
}
private void HandleCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
@@ -321,8 +335,30 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
{
return;
}
var checkedItems = DoCheckedSubTree(item);
try
{
_syncingCheckedItems = true;
foreach (var checkedItem in checkedItems)
{
if (!CheckedItems.Contains(checkedItem))
{
CheckedItems.Add(checkedItem);
}
}
}
finally
{
_syncingCheckedItems = false;
}
}
private ISet<TreeViewItem> DoCheckedSubTree(TreeViewItem item)
{
var checkedItems = new HashSet<TreeViewItem>();
item.SetCurrentValue(TreeViewItem.IsCheckedProperty, true);
checkedItems.Add(item);
if (item.Presenter?.Panel == null && this.GetVisualRoot() is ILayoutRoot visualRoot)
{
var layoutManager = visualRoot.GetLayoutManager();
@@ -336,21 +372,46 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
var control = TreeContainerFromItem(childItem);
if (control is TreeViewItem treeViewItem && treeViewItem.IsEffectiveCheckable())
{
CheckedSubTree(treeViewItem);
var childCheckedItems = DoCheckedSubTree(treeViewItem);
checkedItems.UnionWith(childCheckedItems);
}
}
}
SetupParentNodeCheckedStatus(item);
var (checkedParentItems, _) = SetupParentNodeCheckedStatus(item);
checkedItems.UnionWith(checkedParentItems);
return checkedItems;
}
public void UnCheckedSubTree(TreeViewItem item)
{
if (!item.IsEffectiveCheckable())
{
return;
}
var unCheckedItems = DoUnCheckedSubTree(item);
try
{
_syncingCheckedItems = true;
foreach (var unCheckedItem in unCheckedItems)
{
CheckedItems.Remove(unCheckedItem);
}
}
finally
{
_syncingCheckedItems = false;
}
}
public ISet<TreeViewItem> DoUnCheckedSubTree(TreeViewItem item)
{
var unCheckedItems = new HashSet<TreeViewItem>();
if (item.IsChecked == true)
{
unCheckedItems.Add(item);
}
item.SetCurrentValue(TreeViewItem.IsCheckedProperty, false);
if (item.Presenter?.Panel == null && this.GetVisualRoot() is ILayoutRoot visualRoot)
{
@@ -365,12 +426,14 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
var control = TreeContainerFromItem(childItem);
if (control is TreeViewItem treeViewItem && treeViewItem.IsEffectiveCheckable())
{
UnCheckedSubTree(treeViewItem);
var childUnCheckedItems = DoUnCheckedSubTree(treeViewItem);
unCheckedItems.UnionWith(childUnCheckedItems);
}
}
}
SetupParentNodeCheckedStatus(item);
var (_, unCheckedParentItems) = SetupParentNodeCheckedStatus(item);
unCheckedItems.UnionWith(unCheckedParentItems);
return unCheckedItems;
}
private void UpdatePseudoClasses()
@@ -405,45 +468,9 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
treeViewItem.OwnerTreeView = this;
var disposables = new CompositeDisposable(8);
if (item != null && item is not Visual)
if (item != null && item is not Visual && item is ITreeViewItemData treeViewItemData)
{
if (!treeViewItem.IsSet(TreeViewItem.HeaderProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.HeaderProperty, item);
}
if (item is ITreeViewItemData treeViewItemData)
{
if (!treeViewItem.IsSet(TreeViewItem.IconProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.IconProperty, treeViewItemData.Icon);
}
if (treeViewItem.ItemKey == null)
{
treeViewItem.ItemKey = treeViewItemData.ItemKey;
}
if (!treeViewItem.IsSet(TreeViewItem.IsCheckedProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.IsCheckedProperty, treeViewItemData.IsChecked);
}
if (!treeViewItem.IsSet(TreeViewItem.IsSelectedProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.IsSelectedProperty, treeViewItemData.IsSelected);
}
if (!treeViewItem.IsSet(TreeViewItem.IsEnabledProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.IsEnabledProperty, treeViewItemData.IsEnabled);
}
if (!treeViewItem.IsSet(TreeViewItem.IsExpandedProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.IsExpandedProperty, treeViewItemData.IsExpanded);
}
}
TreeViewItem.ApplyNodeData(treeViewItem, treeViewItemData);
}
if (ItemTemplate != null)
@@ -491,144 +518,7 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
base.OnDetachedFromVisualTree(e);
InteractionHandler.Detach(this);
}
private void SetupParentNodeCheckedStatus(TreeViewItem item)
{
var parent = item.Parent;
while (parent is TreeViewItem parentTreeItem)
{
var isAllChecked = false;
var isAnyChecked = false;
if (parentTreeItem.Items.Count > 0)
{
isAllChecked = parentTreeItem.Items.All(childItem =>
{
if (childItem is TreeViewItem treeViewItem)
{
return treeViewItem.IsChecked.HasValue && treeViewItem.IsChecked.Value;
}
return false;
});
isAnyChecked = parentTreeItem.Items.Any(childItem =>
{
if (childItem is TreeViewItem treeViewItem)
{
return treeViewItem.IsEnabled && (!treeViewItem.IsChecked.HasValue || treeViewItem.IsChecked.HasValue && treeViewItem.IsChecked.Value);
}
return false;
});
}
if (isAllChecked)
{
parentTreeItem.SetCurrentValue(TreeViewItem.IsCheckedProperty, true);
}
else if (isAnyChecked)
{
parentTreeItem.SetCurrentValue(TreeViewItem.IsCheckedProperty, null);
}
else
{
parentTreeItem.SetCurrentValue(TreeViewItem.IsCheckedProperty, false);
}
parent = parent.Parent;
}
}
private void ConfigureDefaultExpandedPaths()
{
if (DefaultExpandedPaths != null)
{
foreach (var defaultExpandedPath in DefaultExpandedPaths)
{
var pathNodes = FindTreeItemByPath(defaultExpandedPath);
ExpandTreeViewPaths(pathNodes);
}
}
}
private void ConfigureDefaultSelectedPaths()
{
if (DefaultSelectedPaths != null)
{
foreach (var defaultSelectedPath in DefaultSelectedPaths)
{
var pathNodes = FindTreeItemByPath(defaultSelectedPath);
if (pathNodes.Count > 0)
{
SelectedItems.Add(pathNodes.Last());
}
}
}
}
private void ConfigureDefaultCheckedPaths()
{
if (DefaultCheckedPaths != null)
{
foreach (var defaultCheckedPath in DefaultCheckedPaths)
{
var pathNodes = FindTreeItemByPath(defaultCheckedPath);
if (pathNodes.Count > 0)
{
var current = pathNodes.Last();
var nodes = new List<ITreeViewItemData>();
nodes.AddRange(CollectionChildItems(current));
CheckedItems.AddRange(nodes);
}
}
}
}
private IList<ITreeViewItemData> CollectionChildItems(ITreeViewItemData item)
{
var list = new List<ITreeViewItemData>();
list.Add(item);
foreach (var child in item.Children)
{
var childList = CollectionChildItems(child);
list.AddRange(childList);
}
return list;
}
private List<TreeViewItem> ExpandTreeViewPaths(IList<ITreeViewItemData> pathNodes)
{
if (pathNodes.Count == 0)
{
return [];
}
List<TreeViewItem> items = new List<TreeViewItem>();
try
{
ItemsControl current = this;
foreach (var pathNode in pathNodes)
{
var child = GetTreeViewItemContainer(pathNode, current);
if (child != null)
{
items.Add(child);
current = child;
child.IsMotionEnabled = false;
child.IsExpanded = true;
}
}
return items;
}
finally
{
foreach (var item in items)
{
item.IsMotionEnabled = true;
}
}
}
private TreeViewItem? GetTreeViewItemContainer(ITreeViewItemData childNode, ItemsControl current)
{
if (current.Presenter?.Panel == null && this.GetVisualRoot() is ILayoutRoot visualRoot)
@@ -639,57 +529,6 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
return current.ContainerFromItem(childNode) as TreeViewItem;
}
private IList<ITreeViewItemData> FindTreeItemByPath(TreeNodePath treeNodePath)
{
if (treeNodePath.Length == 0)
{
return [];
}
var segments = treeNodePath.Segments;
IList<ITreeViewItemData> items = Items.OfType<ITreeViewItemData>().ToList();
IList<ITreeViewItemData> pathNodes = new List<ITreeViewItemData>();
foreach (var segment in segments)
{
bool childFound = false;
for (var i = 0; i < items.Count; i++)
{
var item = items[i];
if (item.ItemKey != null && item.ItemKey.Value == segment)
{
items = item.Children;
childFound = true;
pathNodes.Add(item);
break;
}
}
if (!childFound)
{
return [];
}
}
return pathNodes;
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
if (DefaultSelectedPaths?.Count > 0 || DefaultCheckedPaths?.Count > 0)
{
CollapseAll(false);
}
if (IsDefaultExpandAll)
{
ExpandAll(true);
}
else
{
ConfigureDefaultExpandedPaths();
}
}
private void SubscribeToCheckedItems()
{
if (_checkedItems is INotifyCollectionChanged incc)
@@ -772,14 +611,14 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
break;
}
// if (added?.Count > 0 || removed?.Count > 0)
// {
// var changed = new SelectionChangedEventArgs(
// SelectingItemsControl.SelectionChangedEvent,
// removed ?? Empty,
// added ?? Empty);
// RaiseEvent(changed);
// }
if (added?.Count > 0 || removed?.Count > 0)
{
var changed = new TreeViewCheckedItemsChangedEventArgs(
CheckedItemsChangedEvent,
removed ?? Empty,
added ?? Empty);
RaiseEvent(changed);
}
}
private void CheckedItemsAdded(IList<ITreeViewItemData> items)
@@ -810,4 +649,264 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
{
container.SetCurrentValue(TreeViewItem.IsCheckedProperty, isChecked);
}
#region 默认展开选中
private IList<ITreeViewItemData> FindTreeItemByPath(TreeNodePath treeNodePath)
{
if (treeNodePath.Length == 0)
{
return [];
}
var segments = treeNodePath.Segments;
IList<ITreeViewItemData> items = Items.OfType<ITreeViewItemData>().ToList();
IList<ITreeViewItemData> pathNodes = new List<ITreeViewItemData>();
foreach (var segment in segments)
{
bool childFound = false;
for (var i = 0; i < items.Count; i++)
{
var item = items[i];
if (item.ItemKey != null && item.ItemKey.Value == segment)
{
items = item.Children;
childFound = true;
pathNodes.Add(item);
break;
}
}
if (!childFound)
{
return [];
}
}
return pathNodes;
}
private List<TreeViewItem> ExpandTreeViewPaths(IList<ITreeViewItemData> pathNodes, bool expandLastRecursively = false)
{
if (pathNodes.Count == 0)
{
return [];
}
List<TreeViewItem> items = new List<TreeViewItem>();
try
{
ItemsControl current = this;
for (var i = 0; i < pathNodes.Count; i++)
{
var pathNode = pathNodes[i];
var child = GetTreeViewItemContainer(pathNode, current);
if (child != null)
{
items.Add(child);
current = child;
child.IsMotionEnabled = false;
if (i == pathNodes.Count - 1 && expandLastRecursively)
{
ExpandSubTree(child);
}
else
{
child.SetCurrentValue(TreeViewItem.IsExpandedProperty, true);
}
}
}
return items;
}
finally
{
foreach (var item in items)
{
item.IsMotionEnabled = true;
}
}
}
private List<TreeViewItem> CollapseTreeViewPaths(IList<ITreeViewItemData> pathNodes, bool collapseLastRecursively = false)
{
if (pathNodes.Count == 0)
{
return [];
}
List<TreeViewItem> items = new List<TreeViewItem>();
try
{
ItemsControl current = this;
for (var i = 0; i < pathNodes.Count; i++)
{
var pathNode = pathNodes[i];
var child = GetTreeViewItemContainer(pathNode, current);
if (child != null)
{
items.Add(child);
current = child;
child.IsMotionEnabled = false;
if (i == pathNodes.Count - 1 && collapseLastRecursively)
{
CollapseSubTree(child);
}
else
{
child.SetCurrentValue(TreeViewItem.IsExpandedProperty, false);
}
}
}
return items;
}
finally
{
foreach (var item in items)
{
item.IsMotionEnabled = true;
}
}
}
private (ISet<TreeViewItem>, ISet<TreeViewItem>) SetupParentNodeCheckedStatus(TreeViewItem item)
{
var parent = item.Parent;
var checkedParents = new HashSet<TreeViewItem>();
var unCheckedParents = new HashSet<TreeViewItem>();
while (parent is TreeViewItem parentTreeItem && parentTreeItem.IsEnabled)
{
var isAllChecked = false;
var isAnyChecked = false;
if (parentTreeItem.Items.Count > 0)
{
isAllChecked = parentTreeItem.Items.All(childItem =>
{
if (childItem != null)
{
var container = TreeContainerFromItem(childItem);
if (container is TreeViewItem treeViewItem)
{
return !treeViewItem.IsEffectiveCheckable() || treeViewItem.IsChecked.HasValue && treeViewItem.IsChecked.Value;
}
}
return false;
});
isAnyChecked = parentTreeItem.Items.Any(childItem =>
{
if (childItem != null)
{
var container = TreeContainerFromItem(childItem);
if (container is TreeViewItem treeViewItem)
{
return treeViewItem.IsEffectiveCheckable() && (!treeViewItem.IsChecked.HasValue || treeViewItem.IsChecked.HasValue && treeViewItem.IsChecked.Value);
}
}
return false;
});
}
if (parentTreeItem.IsChecked == true && !isAllChecked)
{
unCheckedParents.Add(parentTreeItem);
}
if (isAllChecked)
{
parentTreeItem.SetCurrentValue(TreeViewItem.IsCheckedProperty, true);
}
else if (isAnyChecked)
{
parentTreeItem.SetCurrentValue(TreeViewItem.IsCheckedProperty, null);
}
else
{
parentTreeItem.SetCurrentValue(TreeViewItem.IsCheckedProperty, false);
}
if (parentTreeItem.IsChecked == true)
{
checkedParents.Add(parentTreeItem);
}
parent = parent.Parent;
}
return (checkedParents, unCheckedParents);
}
private void ConfigureDefaultCheckedPaths()
{
if (DefaultCheckedPaths != null)
{
foreach (var defaultCheckedPath in DefaultCheckedPaths)
{
var pathNodes = FindTreeItemByPath(defaultCheckedPath);
if (pathNodes.Count > 0)
{
try
{
var items = ExpandTreeViewPaths(pathNodes, true);
if (items.Count > 0)
{
var target = items.Last();
target.SetCurrentValue(TreeViewItem.IsCheckedProperty, true);
}
}
finally
{
CollapseTreeViewPaths(pathNodes, false);
}
}
}
}
}
private void ConfigureDefaultExpandedPaths()
{
if (DefaultExpandedPaths != null)
{
foreach (var defaultExpandedPath in DefaultExpandedPaths)
{
var pathNodes = FindTreeItemByPath(defaultExpandedPath);
ExpandTreeViewPaths(pathNodes);
}
}
}
private void ConfigureDefaultSelectedPaths()
{
if (DefaultSelectedPaths != null)
{
foreach (var defaultSelectedPath in DefaultSelectedPaths)
{
var pathNodes = FindTreeItemByPath(defaultSelectedPath);
if (pathNodes.Count > 0)
{
var targetNode = pathNodes.Last();
if (!SelectedItems.Contains(targetNode))
{
SelectedItems.Add(targetNode);
}
}
}
}
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
ConfigureDefaultSelectedPaths();
ConfigureDefaultCheckedPaths();
if (IsDefaultExpandAll)
{
ExpandAll(true);
}
else
{
ConfigureDefaultExpandedPaths();
}
}
#endregion
}
@@ -0,0 +1,30 @@
using System.Collections;
using Avalonia.Interactivity;
namespace AtomUI.Controls;
public class TreeViewCheckedItemsChangedEventArgs : RoutedEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="TreeViewCheckedItemsChangedEventArgs"/> class.
/// </summary>
/// <param name="routedEvent">The event being raised.</param>
/// <param name="removedItems">The items removed from the check.</param>
/// <param name="addedItems">The items added to the check.</param>
public TreeViewCheckedItemsChangedEventArgs(RoutedEvent routedEvent, IList<ITreeViewItemData> removedItems, IList<ITreeViewItemData> addedItems)
: base(routedEvent)
{
RemovedItems = removedItems;
AddedItems = addedItems;
}
/// <summary>
/// Gets the items that were added to the selection.
/// </summary>
public IList<ITreeViewItemData> AddedItems { get; }
/// <summary>
/// Gets the items that were removed from the selection.
/// </summary>
public IList<ITreeViewItemData> RemovedItems { get; }
}
+136 -46
View File
@@ -1,5 +1,8 @@
using AtomUI.Controls.Themes;
using System.Collections.Specialized;
using System.Reactive.Disposables;
using AtomUI.Controls.Themes;
using AtomUI.Controls.Utils;
using AtomUI.Data;
using AtomUI.IconPkg;
using AtomUI.MotionScene;
using AtomUI.Theme.Data;
@@ -265,6 +268,7 @@ public class TreeViewItem : AvaloniaTreeItem, IRadioButton, ITreeViewItemData
private readonly BorderRenderHelper _borderRenderHelper;
private TreeViewItemHeader? _header;
private IDisposable? _borderThicknessDisposable;
private readonly Dictionary<TreeViewItem, CompositeDisposable> _itemsBindingDisposables = new();
static TreeViewItem()
{
@@ -281,7 +285,29 @@ public class TreeViewItem : AvaloniaTreeItem, IRadioButton, ITreeViewItemData
public TreeViewItem()
{
_borderRenderHelper = new BorderRenderHelper();
_borderRenderHelper = new BorderRenderHelper();
LogicalChildren.CollectionChanged += HandleItemsCollectionChanged;
}
private void HandleItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Remove)
{
if (e.OldItems != null)
{
foreach (var item in e.OldItems)
{
if (item is TreeViewItem treeViewItem)
{
if (_itemsBindingDisposables.TryGetValue(treeViewItem, out var disposable))
{
disposable.Dispose();
}
_itemsBindingDisposables.Remove(treeViewItem);
}
}
}
}
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
@@ -456,44 +482,6 @@ public class TreeViewItem : AvaloniaTreeItem, IRadioButton, ITreeViewItemData
return true;
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
if (OwnerTreeView is not null)
{
if (IsChecked != false)
{
if (IsEnabled)
{
SetCurrentValue(IsCheckedProperty, true);
}
else
{
OwnerTreeView.CheckedSubTree(this);
}
}
else
{
var allChecked = false;
var hasAnyChecked = false;
if (Items.Count > 0)
{
allChecked = Items.All(item => OwnerTreeView.CheckedItems.Contains(item));
hasAnyChecked = Items.Any(item => OwnerTreeView.CheckedItems.Contains(item));
}
if (allChecked)
{
SetCurrentValue(IsCheckedProperty, true);
}
else if (hasAnyChecked)
{
SetCurrentValue(IsCheckedProperty, null);
}
}
}
}
public override void Render(DrawingContext context)
{
@@ -543,7 +531,7 @@ public class TreeViewItem : AvaloniaTreeItem, IRadioButton, ITreeViewItemData
if (!IsLeaf && !isLastChild && _itemsPresenterMotionActor?.IsVisible == true)
{
var switcherMiddleBottom = new Point(switcherButtonRect.X + switcherButtonRect.Width / 2, switcherButtonRect.Bottom);
var blockStartPoint = new Point(switcherMiddleBottom.X, switcherMiddleBottom.Y);
var blockStartPoint = new Point(switcherMiddleBottom.X, switcherMiddleBottom.Y);
var blockEndPoint = new Point(blockStartPoint.X, DesiredSize.Height);
context.DrawLine(new Pen(BorderBrush, penWidth), blockStartPoint, blockEndPoint);
}
@@ -582,11 +570,6 @@ public class TreeViewItem : AvaloniaTreeItem, IRadioButton, ITreeViewItemData
includeChildren ? Bounds.Height : _header?.Bounds.Height ?? default));
}
internal Thickness FrameMargin()
{
return _header?.Margin ?? default;
}
internal bool IsInDragBounds(Point point)
{
return GetDragBounds(true).Contains(point);
@@ -633,4 +616,111 @@ public class TreeViewItem : AvaloniaTreeItem, IRadioButton, ITreeViewItemData
}
internal void RaiseClick() => RaiseEvent(new RoutedEventArgs(ClickEvent));
protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey)
{
return new TreeViewItem();
}
protected override bool NeedsContainerOverride(
object? item,
int index,
out object? recycleKey)
{
return NeedsContainer<TreeViewItem>(item, out recycleKey);
}
protected override void ContainerForItemPreparedOverride(
Control container,
object? item,
int index)
{
base.ContainerForItemPreparedOverride(container, item, index);
if (container is TreeViewItem treeViewItem)
{
treeViewItem.OwnerTreeView = OwnerTreeView;
var disposables = new CompositeDisposable(8);
if (item != null && item is not Visual && item is ITreeViewItemData treeViewItemData)
{
ApplyNodeData(treeViewItem, treeViewItemData);
}
if (ItemTemplate != null)
{
disposables.Add(BindUtils.RelayBind(this, ItemTemplateProperty, treeViewItem, TreeViewItem.HeaderTemplateProperty));
}
disposables.Add(BindUtils.RelayBind(this, IsMotionEnabledProperty, treeViewItem, TreeViewItem.IsMotionEnabledProperty));
disposables.Add(BindUtils.RelayBind(this, NodeHoverModeProperty, treeViewItem, TreeViewItem.NodeHoverModeProperty));
disposables.Add(BindUtils.RelayBind(this, IsShowLineProperty, treeViewItem, TreeViewItem.IsShowLineProperty));
disposables.Add(BindUtils.RelayBind(this, IsShowIconProperty, treeViewItem, TreeViewItem.IsShowIconProperty));
disposables.Add(BindUtils.RelayBind(this, IsShowLeafIconProperty, treeViewItem,
TreeViewItem.IsShowLeafIconProperty));
disposables.Add(BindUtils.RelayBind(this, IsSwitcherRotationProperty, treeViewItem, TreeViewItem.IsSwitcherRotationProperty));
disposables.Add(BindUtils.RelayBind(this, ToggleTypeProperty, treeViewItem, TreeViewItem.ToggleTypeProperty));
PrepareTreeViewItem(treeViewItem, item, index, disposables);
if (_itemsBindingDisposables.TryGetValue(treeViewItem, out var oldDisposables))
{
oldDisposables.Dispose();
_itemsBindingDisposables.Remove(treeViewItem);
}
_itemsBindingDisposables.Add(treeViewItem, disposables);
}
else
{
throw new ArgumentOutOfRangeException(nameof(container), "The container type is incorrect, it must be type TreeViewItem.");
}
}
protected virtual void PrepareTreeViewItem(TreeViewItem treeViewItem, object? item, int index, CompositeDisposable compositeDisposable)
{
}
internal static void ApplyNodeData(TreeViewItem treeViewItem, ITreeViewItemData treeViewItemData)
{
if (treeViewItemData is not Visual)
{
if (!treeViewItem.IsSet(TreeViewItem.HeaderProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.HeaderProperty, treeViewItem);
}
if (!treeViewItem.IsSet(TreeViewItem.IconProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.IconProperty, treeViewItemData.Icon);
}
if (treeViewItem.ItemKey == null)
{
treeViewItem.ItemKey = treeViewItemData.ItemKey;
}
if (!treeViewItem.IsSet(TreeViewItem.IsCheckedProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.IsCheckedProperty, treeViewItemData.IsChecked);
}
if (!treeViewItem.IsSet(TreeViewItem.IsSelectedProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.IsSelectedProperty, treeViewItemData.IsSelected);
}
if (!treeViewItem.IsSet(TreeViewItem.IsEnabledProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.IsEnabledProperty, treeViewItemData.IsEnabled);
}
if (!treeViewItem.IsSet(TreeViewItem.IsExpandedProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.IsExpandedProperty, treeViewItemData.IsExpanded);
}
if (!treeViewItem.IsSet(TreeViewItem.IsIndicatorEnabledProperty))
{
treeViewItem.SetCurrentValue(TreeViewItem.IsIndicatorEnabledProperty, treeViewItemData.IsIndicatorEnabled);
}
}
}
}
@@ -7,11 +7,11 @@ public class TreeViewItemData : ITreeViewItemData
public TreeNodeKey? ItemKey { get; set; }
public object? Header { get; set; }
public Icon? Icon { get; set; }
public bool IsEnabled { get; set; }
public bool? IsChecked { get; set; }
public bool IsEnabled { get; set; } = true;
public bool? IsChecked { get; set; } = false;
public bool IsSelected { get; set; }
public bool IsExpanded { get; set; }
public bool IsIndicatorEnabled { get; set; } = true;
public string? GroupName { get; set; }
public IList<ITreeViewItemData> Children { get; } = new List<ITreeViewItemData>();
public IList<ITreeViewItemData> Children { get; set; } = new List<ITreeViewItemData>();
}
@@ -3,13 +3,10 @@ using AtomUI.Animations;
using AtomUI.Controls.Themes;
using AtomUI.Controls.Utils;
using AtomUI.IconPkg;
using AtomUI.Theme.Data;
using AtomUI.Theme.Styling;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;