Refactor TreeView

Add custom tree node expand/close icon
This commit is contained in:
chinboy
2025-12-28 10:04:24 +08:00
parent 3110b531e2
commit 25a53019ea
8 changed files with 326 additions and 148 deletions
@@ -45,6 +45,14 @@ public class TreeViewViewModel : ReactiveObject, IRoutableViewModel
set => this.RaiseAndSetIfChanged(ref _basicTreeViewDefaultExpandedPaths, value);
}
private IList<TreeNodePath>? _customizeCollapseExpandTreeDefaultExpandedPaths;
public IList<TreeNodePath>? CustomizeCollapseExpandTreeDefaultExpandedPaths
{
get => _customizeCollapseExpandTreeDefaultExpandedPaths;
set => this.RaiseAndSetIfChanged(ref _customizeCollapseExpandTreeDefaultExpandedPaths, value);
}
private IList<TreeNodePath>? _basicTreeViewDefaultSelectedPaths;
public IList<TreeNodePath>? BasicTreeViewDefaultSelectedPaths
@@ -31,125 +31,152 @@
</atom:TreeView>
</gallery:ShowCaseItem>
<!-- <gallery:ShowCaseItem -->
<!-- Title="Generate by template" -->
<!-- Description="You can use the Template mechanism to generate tree nodes"> -->
<!-- <atom:TreeView ToggleType="CheckBox" -->
<!-- x:DataType="viewModels:TreeViewViewModel" -->
<!-- DefaultExpandedPaths="{Binding BasicTreeViewDefaultExpandedPaths}" -->
<!-- DefaultSelectedPaths="{Binding BasicTreeViewDefaultSelectedPaths}" -->
<!-- DefaultCheckedPaths="{Binding BasicTreeViewDefaultCheckedPaths}" -->
<!-- ItemsSource="{Binding BasicTreeNodes}"> -->
<!-- <atom:TreeView.ItemTemplate> -->
<!-- <TreeDataTemplate ItemsSource="{Binding Children}"> -->
<!-- <atom:TextBlock Text="{Binding Header}" /> -->
<!-- </TreeDataTemplate> -->
<!-- </atom:TreeView.ItemTemplate> -->
<!-- </atom:TreeView> -->
<!-- </gallery:ShowCaseItem> -->
<!-- -->
<!-- <gallery:ShowCaseItem -->
<!-- Title="Block Node" -->
<!-- Description="Block Node."> -->
<!-- <atom:TreeView ToggleType="CheckBox" IsDefaultExpandAll="True" NodeHoverMode="Block"> -->
<!-- <atom:TreeViewItem Header="parent"> -->
<!-- <atom:TreeViewItem Header="child 1" IsEnabled="False" /> -->
<!-- <atom:TreeViewItem Header="child 2" IsIndicatorEnabled="False"/> -->
<!-- </atom:TreeViewItem> -->
<!-- </atom:TreeView> -->
<!-- </gallery:ShowCaseItem> -->
<!-- -->
<!-- <gallery:ShowCaseItem -->
<!-- Title="Tree with line" -->
<!-- Description="Tree with connected line between nodes, turn on by showLine, customize the preset icon by switcherIcon."> -->
<!-- <StackPanel Orientation="Vertical" Spacing="10"> -->
<!-- <StackPanel Orientation="Horizontal" Spacing="10"> -->
<!-- <TextBlock VerticalAlignment="Center">showLine:</TextBlock> -->
<!-- <atom:ToggleSwitch VerticalAlignment="Center" IsChecked="{Binding ShowLineSwitchChecked,Mode=TwoWay}" /> -->
<!-- </StackPanel> -->
<!-- -->
<!-- <StackPanel Orientation="Horizontal" Spacing="10"> -->
<!-- <TextBlock VerticalAlignment="Center" >showIcon:</TextBlock> -->
<!-- <atom:ToggleSwitch VerticalAlignment="Center" IsChecked="{Binding ShowIconSwitchChecked,Mode=TwoWay}" /> -->
<!-- </StackPanel> -->
<!-- -->
<!-- <StackPanel Orientation="Horizontal" Spacing="10"> -->
<!-- <TextBlock VerticalAlignment="Center">ShowLeafIcon:</TextBlock> -->
<!-- <atom:ToggleSwitch VerticalAlignment="Center" IsChecked="{Binding ShowLeafIconSwitchChecked,Mode=TwoWay}" /> -->
<!-- </StackPanel> -->
<!-- -->
<!-- <StackPanel Orientation="Horizontal" Spacing="10"> -->
<!-- <TextBlock VerticalAlignment="Center">Node hover mode:</TextBlock> -->
<!-- <atom:RadioButton IsChecked="True" IsCheckedChanged="HandleHoverModeChanged" Tag="{x:Static atom:TreeItemHoverMode.Default}">Default</atom:RadioButton> -->
<!-- <atom:RadioButton IsCheckedChanged="HandleHoverModeChanged" Tag="{x:Static atom:TreeItemHoverMode.Block}">Block</atom:RadioButton> -->
<!-- <atom:RadioButton IsCheckedChanged="HandleHoverModeChanged" Tag="{x:Static atom:TreeItemHoverMode.WholeLine}">WholeLine</atom:RadioButton> -->
<!-- </StackPanel> -->
<!-- -->
<!-- <atom:TreeView IsShowLine="{Binding ShowLineSwitchChecked}" -->
<!-- IsShowIcon="{Binding ShowIconSwitchChecked}" -->
<!-- IsShowLeafIcon="{Binding ShowLeafIconSwitchChecked}" -->
<!-- NodeHoverMode="{Binding TreeViewNodeHoverMode}" -->
<!-- IsSwitcherRotation="False" -->
<!-- x:DataType="viewModels:TreeViewViewModel"> -->
<!-- <atom:TreeViewItem Header="parent 1" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" -->
<!-- IsExpanded="True"> -->
<!-- <atom:TreeViewItem Header="parent 1-0" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" -->
<!-- IsExpanded="True"> -->
<!-- <atom:TreeViewItem Header="leaf 1" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" /> -->
<!-- <atom:TreeViewItem Header="leaf 2" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" /> -->
<!-- </atom:TreeViewItem> -->
<!-- <atom:TreeViewItem Header="parent 1-1"> -->
<!-- <atom:TreeViewItem Header="leaf" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" /> -->
<!-- </atom:TreeViewItem> -->
<!-- <atom:TreeViewItem Header="parent 1-2"> -->
<!-- <atom:TreeViewItem Header="leaf 1" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" /> -->
<!-- <atom:TreeViewItem Header="leaf 2" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" /> -->
<!-- </atom:TreeViewItem> -->
<!-- </atom:TreeViewItem> -->
<!-- <atom:TreeViewItem Header="parent 2"> -->
<!-- <atom:TreeViewItem Header="parent 2-0" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}"> -->
<!-- <atom:TreeViewItem Header="leaf 1" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" /> -->
<!-- <atom:TreeViewItem Header="leaf 2" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" /> -->
<!-- </atom:TreeViewItem> -->
<!-- </atom:TreeViewItem> -->
<!-- </atom:TreeView> -->
<!-- </StackPanel> -->
<!-- </gallery:ShowCaseItem> -->
<!-- -->
<!-- <gallery:ShowCaseItem -->
<!-- Title="draggable" -->
<!-- Description="Drag treeNode to insert after the other treeNode or insert into the other parent TreeNode." -->
<!-- Margin="0, 0, 10, 0"> -->
<!-- <atom:TreeView IsDraggable="True" NodeHoverMode="Block"> -->
<!-- <atom:TreeViewItem Header="0-0"> -->
<!-- <atom:TreeViewItem Header="0-0-0"> -->
<!-- <atom:TreeViewItem Header="0-0-0-0" /> -->
<!-- <atom:TreeViewItem Header="0-0-0-1" /> -->
<!-- <atom:TreeViewItem Header="0-0-0-2" /> -->
<!-- </atom:TreeViewItem> -->
<!-- <atom:TreeViewItem Header="0-0-1"> -->
<!-- <atom:TreeViewItem Header="0-0-1-0" /> -->
<!-- <atom:TreeViewItem Header="0-0-1-1" /> -->
<!-- <atom:TreeViewItem Header="0-0-1-2" /> -->
<!-- </atom:TreeViewItem> -->
<!-- <atom:TreeViewItem Header="0-0-2" /> -->
<!-- </atom:TreeViewItem> -->
<!-- <atom:TreeViewItem Header="0-1"> -->
<!-- <atom:TreeViewItem Header="0-1-0"> -->
<!-- <atom:TreeViewItem Header="0-1-0-0" /> -->
<!-- <atom:TreeViewItem Header="0-1-0-1" /> -->
<!-- <atom:TreeViewItem Header="0-1-0-2" /> -->
<!-- </atom:TreeViewItem> -->
<!-- <atom:TreeViewItem Header="0-1-1"> -->
<!-- <atom:TreeViewItem Header="0-1-1-0" /> -->
<!-- <atom:TreeViewItem Header="0-1-1-1" /> -->
<!-- <atom:TreeViewItem Header="0-1-1-2" /> -->
<!-- </atom:TreeViewItem> -->
<!-- <atom:TreeViewItem Header="0-1-2" /> -->
<!-- </atom:TreeViewItem> -->
<!-- <atom:TreeViewItem Header="0-2" /> -->
<!-- </atom:TreeView> -->
<!-- </gallery:ShowCaseItem> -->
<gallery:ShowCaseItem
Title="Generate by template"
Description="You can use the Template mechanism to generate tree nodes">
<atom:TreeView ToggleType="CheckBox"
x:DataType="viewModels:TreeViewViewModel"
DefaultExpandedPaths="{Binding BasicTreeViewDefaultExpandedPaths}"
DefaultSelectedPaths="{Binding BasicTreeViewDefaultSelectedPaths}"
DefaultCheckedPaths="{Binding BasicTreeViewDefaultCheckedPaths}"
ItemsSource="{Binding BasicTreeNodes}">
<atom:TreeView.ItemTemplate>
<TreeDataTemplate ItemsSource="{Binding Children}">
<atom:TextBlock Text="{Binding Header}" />
</TreeDataTemplate>
</atom:TreeView.ItemTemplate>
</atom:TreeView>
</gallery:ShowCaseItem>
<gallery:ShowCaseItem
Title="Block Node"
Description="Block Node.">
<atom:TreeView ToggleType="CheckBox" IsDefaultExpandAll="True" NodeHoverMode="Block">
<atom:TreeViewItem Header="parent">
<atom:TreeViewItem Header="child 1" IsEnabled="False" />
<atom:TreeViewItem Header="child 2" IsIndicatorEnabled="False"/>
</atom:TreeViewItem>
</atom:TreeView>
</gallery:ShowCaseItem>
<gallery:ShowCaseItem
Title="Tree with line"
Description="Tree with connected line between nodes, turn on by showLine, customize the preset icon by switcherIcon.">
<StackPanel Orientation="Vertical" Spacing="10">
<StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock VerticalAlignment="Center">showLine:</TextBlock>
<atom:ToggleSwitch VerticalAlignment="Center" IsChecked="{Binding ShowLineSwitchChecked,Mode=TwoWay}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock VerticalAlignment="Center" >showIcon:</TextBlock>
<atom:ToggleSwitch VerticalAlignment="Center" IsChecked="{Binding ShowIconSwitchChecked,Mode=TwoWay}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock VerticalAlignment="Center">ShowLeafIcon:</TextBlock>
<atom:ToggleSwitch VerticalAlignment="Center" IsChecked="{Binding ShowLeafIconSwitchChecked,Mode=TwoWay}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock VerticalAlignment="Center">Node hover mode:</TextBlock>
<atom:RadioButton IsChecked="True" IsCheckedChanged="HandleHoverModeChanged" Tag="{x:Static atom:TreeItemHoverMode.Default}">Default</atom:RadioButton>
<atom:RadioButton IsCheckedChanged="HandleHoverModeChanged" Tag="{x:Static atom:TreeItemHoverMode.Block}">Block</atom:RadioButton>
<atom:RadioButton IsCheckedChanged="HandleHoverModeChanged" Tag="{x:Static atom:TreeItemHoverMode.WholeLine}">WholeLine</atom:RadioButton>
</StackPanel>
<atom:TreeView IsShowLine="{Binding ShowLineSwitchChecked}"
IsShowIcon="{Binding ShowIconSwitchChecked}"
IsShowLeafIcon="{Binding ShowLeafIconSwitchChecked}"
NodeHoverMode="{Binding TreeViewNodeHoverMode}"
IsSwitcherRotation="False"
x:DataType="viewModels:TreeViewViewModel">
<atom:TreeViewItem Header="parent 1" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}"
IsExpanded="True">
<atom:TreeViewItem Header="parent 1-0" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}"
IsExpanded="True">
<atom:TreeViewItem Header="leaf 1" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" />
<atom:TreeViewItem Header="leaf 2" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" />
</atom:TreeViewItem>
<atom:TreeViewItem Header="parent 1-1">
<atom:TreeViewItem Header="leaf" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" />
</atom:TreeViewItem>
<atom:TreeViewItem Header="parent 1-2">
<atom:TreeViewItem Header="leaf 1" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" />
<atom:TreeViewItem Header="leaf 2" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" />
</atom:TreeViewItem>
</atom:TreeViewItem>
<atom:TreeViewItem Header="parent 2">
<atom:TreeViewItem Header="parent 2-0" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}">
<atom:TreeViewItem Header="leaf 1" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" />
<atom:TreeViewItem Header="leaf 2" Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" />
</atom:TreeViewItem>
</atom:TreeViewItem>
</atom:TreeView>
</StackPanel>
</gallery:ShowCaseItem>
<gallery:ShowCaseItem
Title="draggable"
Description="Drag treeNode to insert after the other treeNode or insert into the other parent TreeNode."
Margin="0, 0, 10, 0">
<atom:TreeView IsDraggable="True" NodeHoverMode="Block">
<atom:TreeViewItem Header="0-0">
<atom:TreeViewItem Header="0-0-0">
<atom:TreeViewItem Header="0-0-0-0" />
<atom:TreeViewItem Header="0-0-0-1" />
<atom:TreeViewItem Header="0-0-0-2" />
</atom:TreeViewItem>
<atom:TreeViewItem Header="0-0-1">
<atom:TreeViewItem Header="0-0-1-0" />
<atom:TreeViewItem Header="0-0-1-1" />
<atom:TreeViewItem Header="0-0-1-2" />
</atom:TreeViewItem>
<atom:TreeViewItem Header="0-0-2" />
</atom:TreeViewItem>
<atom:TreeViewItem Header="0-1">
<atom:TreeViewItem Header="0-1-0">
<atom:TreeViewItem Header="0-1-0-0" />
<atom:TreeViewItem Header="0-1-0-1" />
<atom:TreeViewItem Header="0-1-0-2" />
</atom:TreeViewItem>
<atom:TreeViewItem Header="0-1-1">
<atom:TreeViewItem Header="0-1-1-0" />
<atom:TreeViewItem Header="0-1-1-1" />
<atom:TreeViewItem Header="0-1-1-2" />
</atom:TreeViewItem>
<atom:TreeViewItem Header="0-1-2" />
</atom:TreeViewItem>
<atom:TreeViewItem Header="0-2" />
</atom:TreeView>
</gallery:ShowCaseItem>
<gallery:ShowCaseItem
Title="Customize collapse/expand icon"
Description="customize collapse/expand icon of tree node">
<atom:TreeView Name="CustomizeCollapseExpandTree" DefaultExpandedPaths="{Binding CustomizeCollapseExpandTreeDefaultExpandedPaths}"
IsSwitcherRotation="True">
<atom:TreeView.SwitcherRotationIcon>
<atom:IconTemplate>
<antdicons:RightOutlined/>
</atom:IconTemplate>
</atom:TreeView.SwitcherRotationIcon>
<atom:TreeViewItem Header="parent 1" ItemKey="0-0">
<atom:TreeViewItem Header="parent 1-0" ItemKey="0-0-0">
<atom:TreeViewItem Header="leaf" ItemKey="0-0-0-0"/>
<atom:TreeViewItem Header="leaf" ItemKey="0-0-0-1" />
<atom:TreeViewItem Header="leaf" ItemKey="0-0-0-2" />
</atom:TreeViewItem>
<atom:TreeViewItem Header="parent 1-1" ItemKey="0-0-1">
<atom:TreeViewItem Header="leaf" ItemKey="0-0-1-0"/>
</atom:TreeViewItem>
<atom:TreeViewItem Header="parent 1-2" ItemKey="0-0-2">
<atom:TreeViewItem Header="leaf" ItemKey="0-0-2-0"/>
<atom:TreeViewItem Header="leaf" ItemKey="0-0-2-1"/>
</atom:TreeViewItem>
</atom:TreeViewItem>
</atom:TreeView>
</gallery:ShowCaseItem>
</gallery:ShowCasePanel>
</UserControl>
@@ -18,6 +18,7 @@ public partial class TreeViewShowCase : ReactiveUserControl<TreeViewViewModel>
InitBasicTreeViewData(viewModel);
viewModel.TreeViewNodeHoverMode = TreeItemHoverMode.Default;
InitBasicTreeNodes(viewModel);
InitCustomizeCollapseExpandTreeDefaultExpandedPaths(viewModel);
}
});
InitializeComponent();
@@ -119,4 +120,11 @@ public partial class TreeViewShowCase : ReactiveUserControl<TreeViewViewModel>
}
];
}
private void InitCustomizeCollapseExpandTreeDefaultExpandedPaths(TreeViewViewModel viewModel)
{
viewModel.CustomizeCollapseExpandTreeDefaultExpandedPaths = [
new TreeNodePath("0-0/0-0-0")
];
}
}
@@ -0,0 +1,24 @@
using Avalonia.Controls;
using Avalonia.Styling;
namespace AtomUI.Controls;
public interface IIconTemplate : ITemplate<PathIcon?>
{}
public class IconFuncTemplate : IIconTemplate
{
private readonly Func<PathIcon?> _func;
public IconFuncTemplate(Func<PathIcon?> func)
{
_func = func ?? throw new ArgumentNullException(nameof(func));
}
public PathIcon? Build()
{
return _func();
}
object? ITemplate.Build() => Build();
}
@@ -0,0 +1,16 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml.Templates;
using Avalonia.Metadata;
using Avalonia.Styling;
namespace AtomUI.Controls;
[ControlTemplateScope]
public class IconTemplate : IIconTemplate
{
[Content]
[TemplateContent]
public object? Content { get; set; }
public PathIcon? Build() => (PathIcon?)TemplateContent.Load(Content)?.Result;
object? ITemplate.Build() => Build();
}
@@ -22,6 +22,7 @@
CollapseIcon="{TemplateBinding SwitcherCollapseIcon}"
ExpandIcon="{TemplateBinding SwitcherExpandIcon}"
LoadingIcon="{TemplateBinding SwitcherLoadingIcon}"
RotationIcon="{TemplateBinding SwitcherRotationIcon}"
LeafIcon="{TemplateBinding SwitcherLeafIcon}"
IsChecked="{TemplateBinding IsExpanded, Mode=TwoWay}"
IsLoading="{TemplateBinding IsLoading}" />
@@ -289,15 +289,6 @@ public partial class TreeView
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == DefaultSelectedPathsProperty)
{
ConfigureDefaultSelectedPaths();
}
}
private void HandlePrepareDrag()
{
_beingDraggedTreeItem = GetNodeByPositionSelfFirst(_lastPoint!.Value);
+123 -20
View File
@@ -43,20 +43,20 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
public static readonly StyledProperty<TreeItemHoverMode> NodeHoverModeProperty =
AvaloniaProperty.Register<TreeView, TreeItemHoverMode>(nameof(NodeHoverMode), TreeItemHoverMode.Default);
public static readonly StyledProperty<PathIcon?> SwitcherExpandIconProperty =
AvaloniaProperty.Register<TreeView, PathIcon?>(nameof(SwitcherExpandIcon));
public static readonly StyledProperty<IconTemplate?> SwitcherExpandIconProperty =
AvaloniaProperty.Register<TreeView, IconTemplate?>(nameof(SwitcherExpandIcon));
public static readonly StyledProperty<PathIcon?> SwitcherCollapseIconProperty =
AvaloniaProperty.Register<TreeView, PathIcon?>(nameof(SwitcherCollapseIcon));
public static readonly StyledProperty<IconTemplate?> SwitcherCollapseIconProperty =
AvaloniaProperty.Register<TreeView, IconTemplate?>(nameof(SwitcherCollapseIcon));
public static readonly StyledProperty<PathIcon?> SwitcherRotationIconProperty =
AvaloniaProperty.Register<TreeView, PathIcon?>(nameof(SwitcherRotationIcon));
public static readonly StyledProperty<IconTemplate?> SwitcherRotationIconProperty =
AvaloniaProperty.Register<TreeView, IconTemplate?>(nameof(SwitcherRotationIcon));
public static readonly StyledProperty<PathIcon?> SwitcherLoadingIconProperty =
AvaloniaProperty.Register<TreeView, PathIcon?>(nameof(SwitcherRotationIcon));
public static readonly StyledProperty<IconTemplate?> SwitcherLoadingIconProperty =
AvaloniaProperty.Register<TreeView, IconTemplate?>(nameof(SwitcherRotationIcon));
public static readonly StyledProperty<PathIcon?> SwitcherLeafIconProperty =
AvaloniaProperty.Register<TreeView, PathIcon?>(nameof(SwitcherLeafIcon));
public static readonly StyledProperty<IconTemplate?> SwitcherLeafIconProperty =
AvaloniaProperty.Register<TreeView, IconTemplate?>(nameof(SwitcherLeafIcon));
public static readonly StyledProperty<bool> IsShowLeafIconProperty =
AvaloniaProperty.Register<TreeView, bool>(nameof(IsShowLeafIcon));
@@ -118,31 +118,31 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
set => SetValue(NodeHoverModeProperty, value);
}
public PathIcon? SwitcherExpandIcon
public IconTemplate? SwitcherExpandIcon
{
get => GetValue(SwitcherExpandIconProperty);
set => SetValue(SwitcherExpandIconProperty, value);
}
public PathIcon? SwitcherCollapseIcon
public IconTemplate? SwitcherCollapseIcon
{
get => GetValue(SwitcherCollapseIconProperty);
set => SetValue(SwitcherCollapseIconProperty, value);
}
public PathIcon? SwitcherRotationIcon
public IconTemplate? SwitcherRotationIcon
{
get => GetValue(SwitcherRotationIconProperty);
set => SetValue(SwitcherRotationIconProperty, value);
}
public PathIcon? SwitcherLoadingIcon
public IconTemplate? SwitcherLoadingIcon
{
get => GetValue(SwitcherLoadingIconProperty);
set => SetValue(SwitcherLoadingIconProperty, value);
}
public PathIcon? SwitcherLeafIcon
public IconTemplate? SwitcherLeafIcon
{
get => GetValue(SwitcherLeafIconProperty);
set => SetValue(SwitcherLeafIconProperty, value);
@@ -522,6 +522,12 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
disposables.Add(BindUtils.RelayBind(this, ItemTemplateProperty, treeViewItem, TreeViewItem.HeaderTemplateProperty));
}
SetTreeViewItemIcon(treeViewItem, TreeViewItem.SwitcherExpandIconProperty, SwitcherExpandIcon);
SetTreeViewItemIcon(treeViewItem, TreeViewItem.SwitcherCollapseIconProperty, SwitcherCollapseIcon);
SetTreeViewItemIcon(treeViewItem, TreeViewItem.SwitcherRotationIconProperty, SwitcherRotationIcon);
SetTreeViewItemIcon(treeViewItem, TreeViewItem.SwitcherLoadingIconProperty, SwitcherLoadingIcon);
SetTreeViewItemIcon(treeViewItem, TreeViewItem.SwitcherLeafIconProperty, SwitcherLeafIcon);
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));
@@ -530,11 +536,6 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
TreeViewItem.IsShowLeafIconProperty));
disposables.Add(BindUtils.RelayBind(this, IsSwitcherRotationProperty, treeViewItem, TreeViewItem.IsSwitcherRotationProperty));
disposables.Add(BindUtils.RelayBind(this, ToggleTypeProperty, treeViewItem, TreeViewItem.ToggleTypeProperty));
disposables.Add(BindUtils.RelayBind(this, SwitcherExpandIconProperty, treeViewItem, TreeViewItem.SwitcherExpandIconProperty));
disposables.Add(BindUtils.RelayBind(this, SwitcherCollapseIconProperty, treeViewItem, TreeViewItem.SwitcherCollapseIconProperty));
disposables.Add(BindUtils.RelayBind(this, SwitcherRotationIconProperty, treeViewItem, TreeViewItem.SwitcherRotationIconProperty));
disposables.Add(BindUtils.RelayBind(this, SwitcherLoadingIconProperty, treeViewItem, TreeViewItem.SwitcherLoadingIconProperty));
disposables.Add(BindUtils.RelayBind(this, SwitcherLeafIconProperty, treeViewItem, TreeViewItem.SwitcherLeafIconProperty));
PrepareTreeViewItem(treeViewItem, item, index, disposables);
@@ -550,6 +551,19 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
throw new ArgumentOutOfRangeException(nameof(container), "The container type is incorrect, it must be type TreeViewItem.");
}
}
private void SetTreeViewItemIcon(TreeViewItem treeViewItem, AvaloniaProperty iconProperty, IIconTemplate? iconTemplate)
{
if (iconTemplate == null)
{
treeViewItem.SetValue(iconProperty, null);
}
else
{
treeViewItem.SetValue(iconProperty, iconTemplate.Build());
}
}
protected virtual void PrepareTreeViewItem(TreeViewItem treeViewItem, object? item, int index, CompositeDisposable compositeDisposable)
{
@@ -980,4 +994,93 @@ public partial class TreeView : AvaloniaTreeView, IMotionAwareControl, IControlS
}
#endregion
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == DefaultSelectedPathsProperty)
{
ConfigureDefaultSelectedPaths();
}
else if (change.Property == SwitcherRotationIconProperty)
{
HandleSwitcherRotationIconChanged();
}
else if (change.Property == SwitcherExpandIconProperty)
{
HandleSwitcherExpandIconChanged();
}
else if (change.Property == SwitcherCollapseIconProperty)
{
HandleSwitcherCollapseIconChanged();
}
else if (change.Property == SwitcherLoadingIconProperty)
{
HandleSwitcherLoadingIconChanged();
}
else if (change.Property == SwitcherLeafIconProperty)
{
HandleSwitcherLeafIconChanged();
}
}
protected void HandleSwitcherRotationIconChanged()
{
for (var i = 0; i < ItemCount; i++)
{
var container = ContainerFromIndex(i);
if (container is TreeViewItem treeViewItem)
{
SetTreeViewItemIcon(treeViewItem, TreeViewItem.SwitcherRotationIconProperty, SwitcherRotationIcon);
}
}
}
protected void HandleSwitcherExpandIconChanged()
{
for (var i = 0; i < ItemCount; i++)
{
var container = ContainerFromIndex(i);
if (container is TreeViewItem treeViewItem)
{
SetTreeViewItemIcon(treeViewItem, TreeViewItem.SwitcherExpandIconProperty, SwitcherExpandIcon);
}
}
}
protected void HandleSwitcherCollapseIconChanged()
{
for (var i = 0; i < ItemCount; i++)
{
var container = ContainerFromIndex(i);
if (container is TreeViewItem treeViewItem)
{
SetTreeViewItemIcon(treeViewItem, TreeViewItem.SwitcherCollapseIconProperty, SwitcherCollapseIcon);
}
}
}
protected void HandleSwitcherLoadingIconChanged()
{
for (var i = 0; i < ItemCount; i++)
{
var container = ContainerFromIndex(i);
if (container is TreeViewItem treeViewItem)
{
SetTreeViewItemIcon(treeViewItem, TreeViewItem.SwitcherLoadingIconProperty, SwitcherLoadingIcon);
}
}
}
protected void HandleSwitcherLeafIconChanged()
{
for (var i = 0; i < ItemCount; i++)
{
var container = ContainerFromIndex(i);
if (container is TreeViewItem treeViewItem)
{
SetTreeViewItemIcon(treeViewItem, TreeViewItem.SwitcherLeafIconProperty, SwitcherLeafIcon);
}
}
}
}