Refactor treeview

add ToggleType support
This commit is contained in:
CHINBOY
2025-06-26 23:10:47 +08:00
parent 525edf1a74
commit 38b75310b5
6 changed files with 75 additions and 113 deletions
@@ -151,6 +151,10 @@ internal class DataGridFilterIndicator : IconButton
Placement = PlacementMode.BottomEdgeAlignedRight,
IsDetectMouseClickEnabled = false
};
BindUtils.RelayBind(this, FilterMultipleProperty, treeFlyout, DataGridTreeFilterFlyout.ToggleTypeProperty, (v) =>
{
return v ? ItemToggleType.CheckBox : ItemToggleType.Radio;
});
BindUtils.RelayBind(owningGrid, MotionAwareControlProperty.IsMotionEnabledProperty, treeFlyout,
MotionAwareControlProperty.IsMotionEnabledProperty);
var selectAllTreeItem = new DataGridFilterTreeItem();
@@ -208,7 +212,7 @@ internal class DataGridFilterIndicator : IconButton
Header = item.Text,
FilterValue = item.Value
};
// BindUtils.RelayBind(this, ToggleTypeProperty, treeItem, TreeViewItem.ToggleTypeProperty);
treeItems.Add(treeItem);
if (item.Children.Count > 0)
{
@@ -1,13 +1,22 @@
using AtomUI.Data;
using AtomUI.MotionScene;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Metadata;
namespace AtomUI.Controls;
internal class DataGridTreeFilterFlyout : TreeViewFlyout
{
internal static readonly StyledProperty<ItemToggleType> ToggleTypeProperty =
TreeView.ToggleTypeProperty.AddOwner<DataGridTreeFilterFlyout>();
public ItemToggleType ToggleType
{
get => GetValue(ToggleTypeProperty);
set => SetValue(ToggleTypeProperty, value);
}
public event EventHandler<DataGridFilterValuesSelectedEventArgs>? FilterValuesSelected;
public DataGridTreeFilterFlyout()
@@ -21,11 +30,11 @@ internal class DataGridTreeFilterFlyout : TreeViewFlyout
var presenter = new DataGridTreeFilterFlyoutPresenter
{
IsDefaultExpandAll = true,
ItemsSource = Items,
IsCheckable = true
ItemsSource = Items
};
BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, presenter, MenuFlyoutPresenter.IsShowArrowProperty);
BindUtils.RelayBind(this, IsMotionEnabledProperty, presenter, MenuFlyoutPresenter.IsMotionEnabledProperty);
BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, presenter, DataGridTreeFilterFlyoutPresenter.IsShowArrowProperty);
BindUtils.RelayBind(this, IsMotionEnabledProperty, presenter, DataGridTreeFilterFlyoutPresenter.IsMotionEnabledProperty);
BindUtils.RelayBind(this, ToggleTypeProperty, presenter, DataGridTreeFilterFlyoutPresenter.ToggleTypeProperty);
return presenter;
}
@@ -39,18 +48,6 @@ internal class DataGridTreeFilterFlyout : TreeViewFlyout
internal class DataGridFilterTreeItem : TreeViewItem
{
public string? FilterValue { get; set; }
protected override void NotifyHeaderClick()
{
if (IsChecked is null)
{
IsChecked = true;
}
else
{
IsChecked = !IsChecked;
}
}
protected override void OnHeaderDoubleTapped(TappedEventArgs e)
{
@@ -4,7 +4,7 @@
xmlns:atom="https://atomui.net"
x:Class="AtomUI.Controls.Themes.TreeViewItemTheme">
<Setter Property="Template">
<ControlTemplate>
<ControlTemplate TargetType="atom:TreeViewItem">
<StackPanel Orientation="Vertical">
<Border Name="{x:Static atom:TreeViewItemThemeConstants.FramePart}"
Focusable="True"
@@ -24,12 +24,22 @@
LeafIcon="{TemplateBinding SwitcherLeafIcon}"
IsChecked="{TemplateBinding IsExpanded, Mode=TwoWay}"
IsLoading="{TemplateBinding IsLoading}" />
<atom:CheckBox HorizontalAlignment="Left"
<atom:CheckBox Name="{x:Static atom:TreeViewItemThemeConstants.ToggleCheckboxPart}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Grid.Column="1"
IsVisible="{TemplateBinding IsCheckboxVisible}"
IsEnabled="{TemplateBinding IsCheckboxEnable}"
IsChecked="{TemplateBinding IsChecked, Mode=TwoWay}" />
IsChecked="{TemplateBinding IsChecked}"
IsEnabled="{TemplateBinding IsEnabled}"
IsVisible="False" />
<atom:RadioButton Name="{x:Static atom:TreeViewItemThemeConstants.ToggleRadioPart}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Grid.Column="1"
IsChecked="{TemplateBinding IsChecked}"
GroupName="{TemplateBinding GroupName}"
IsVisible="False" />
<atom:IconPresenter Name="{x:Static atom:TreeViewItemThemeConstants.IconPresenterPart}"
Grid.Column="2"
Icon="{TemplateBinding Icon}"
@@ -101,6 +111,19 @@
<Setter Property="EffectiveNodeBg"
Value="{DynamicResource {x:Static atom:TreeViewTokenKey.NodeSelectedBg}}" />
</Style>
<Style Selector="^[ToggleType=CheckBox]">
<Style Selector="^ /template/ atom|CheckBox#PART_ToggleCheckbox">
<Setter Property="IsVisible" Value="True" />
</Style>
</Style>
<Style Selector="^[ToggleType=Radio]">
<Style Selector="^ /template/ atom|RadioButton#PART_ToggleRadio">
<Setter Property="IsVisible" Value="True" />
</Style>
</Style>
<!-- BuildCommonStyle 结束 -->
<!-- BuildSwitcherButtonStyle 开始 -->
@@ -122,7 +145,7 @@
</Style>
</Style>
<Style Selector="^[IsCheckboxVisible=True]">
<Style Selector="^[ToggleType=CheckBox], ^[ToggleType=Radio]">
<Style Selector="^ /template/ atom|NodeSwitcherButton#PART_NodeSwitcherButton">
<Setter Property="Margin"
Value="{DynamicResource {x:Static atom:TreeViewTokenKey.TreeNodeSwitcherMargin}}" />
@@ -9,6 +9,8 @@ internal static class TreeViewItemThemeConstants
public const string HeaderPresenterPart = "PART_HeaderPresenter";
public const string IconPresenterPart = "PART_IconPresenter";
public const string NodeSwitcherButtonPart = "PART_NodeSwitcherButton";
public const string ToggleCheckboxPart = "PART_ToggleCheckbox";
public const string ToggleRadioPart = "PART_ToggleRadio";
}
internal static class NodeSwitcherButtonThemeConstants
+13 -23
View File
@@ -35,9 +35,6 @@ public class TreeView : AvaloniaTreeView,
public static readonly StyledProperty<bool> IsDraggableProperty =
AvaloniaProperty.Register<TreeView, bool>(nameof(IsDraggable));
public static readonly StyledProperty<bool> IsCheckableProperty =
AvaloniaProperty.Register<TreeView, bool>(nameof(IsCheckable));
public static readonly StyledProperty<bool> IsShowIconProperty =
AvaloniaProperty.Register<TreeView, bool>(nameof(IsShowIcon));
@@ -61,19 +58,16 @@ public class TreeView : AvaloniaTreeView,
public static readonly StyledProperty<AbstractMotion?> CloseMotionProperty =
Popup.CloseMotionProperty.AddOwner<TreeView>();
public static readonly StyledProperty<ItemToggleType> ToggleTypeProperty =
AvaloniaProperty.Register<TreeView, ItemToggleType>(nameof(ToggleType), ItemToggleType.None);
public bool IsDraggable
{
get => GetValue(IsDraggableProperty);
set => SetValue(IsDraggableProperty, value);
}
public bool IsCheckable
{
get => GetValue(IsCheckableProperty);
set => SetValue(IsCheckableProperty, value);
}
public bool IsShowIcon
{
get => GetValue(IsShowIconProperty);
@@ -122,6 +116,12 @@ public class TreeView : AvaloniaTreeView,
set => SetValue(CloseMotionProperty, value);
}
public ItemToggleType ToggleType
{
get => GetValue(ToggleTypeProperty);
set => SetValue(ToggleTypeProperty, value);
}
public bool IsDefaultExpandAll { get; set; } = false;
#endregion
@@ -239,12 +239,7 @@ public class TreeView : AvaloniaTreeView,
public void CheckedSubTree(TreeViewItem item)
{
if (!IsCheckable)
{
return;
}
if (!item.IsEnabled || !item.IsCheckable)
if (!item.IsEnabled || item.ToggleType == ItemToggleType.None)
{
return;
}
@@ -272,12 +267,7 @@ public class TreeView : AvaloniaTreeView,
public void UnCheckedSubTree(TreeViewItem item)
{
if (!IsCheckable)
{
return;
}
if (!item.IsEnabled || !item.IsCheckable)
if (!item.IsEnabled || item.ToggleType == ItemToggleType.None)
{
return;
}
@@ -339,8 +329,8 @@ public class TreeView : AvaloniaTreeView,
BindUtils.RelayBind(this, IsShowIconProperty, treeViewItem, TreeViewItem.IsShowIconProperty);
BindUtils.RelayBind(this, IsShowLeafIconProperty, treeViewItem,
TreeViewItem.IsShowLeafIconProperty);
BindUtils.RelayBind(this, IsCheckableProperty, treeViewItem, TreeViewItem.IsCheckboxVisibleProperty);
BindUtils.RelayBind(this, IsSwitcherRotationProperty, treeViewItem, TreeViewItem.IsSwitcherRotationProperty);
BindUtils.RelayBind(this, ToggleTypeProperty, treeViewItem, TreeViewItem.ToggleTypeProperty);
}
}
+12 -66
View File
@@ -28,13 +28,9 @@ using AvaloniaTreeItem = Avalonia.Controls.TreeViewItem;
[PseudoClasses(TreeViewPseudoClass.NodeToggleTypeCheckBox, TreeViewPseudoClass.NodeToggleTypeRadio, TreeViewPseudoClass.TreeNodeHover)]
public class TreeViewItem : AvaloniaTreeItem,
IResourceBindingManager,
IRadioButton
IResourceBindingManager
{
#region 公共属性定义
public static readonly StyledProperty<bool> IsCheckableProperty =
AvaloniaProperty.Register<TreeViewItem, bool>(nameof(IsCheckable), true);
public static readonly StyledProperty<Icon?> IconProperty
= AvaloniaProperty.Register<TreeViewItem, Icon?>(nameof(Icon));
@@ -67,18 +63,9 @@ public class TreeViewItem : AvaloniaTreeItem,
public static readonly StyledProperty<bool> IsLoadingProperty =
AvaloniaProperty.Register<TreeViewItem, bool>(nameof(IsLoading), false);
public static readonly StyledProperty<ItemToggleType> ToggleTypeProperty =
AvaloniaProperty.Register<TreeViewItem, ItemToggleType>(nameof(ToggleType));
public static readonly StyledProperty<string?> GroupNameProperty =
RadioButton.GroupNameProperty.AddOwner<TreeViewItem>();
public bool IsCheckable
{
get => GetValue(IsCheckableProperty);
set => SetValue(IsCheckableProperty, value);
}
public Icon? Icon
{
get => GetValue(IconProperty);
@@ -140,12 +127,6 @@ public class TreeViewItem : AvaloniaTreeItem,
get => GetValue(IsLoadingProperty);
set => SetValue(IsLoadingProperty, value);
}
public ItemToggleType ToggleType
{
get => GetValue(ToggleTypeProperty);
set => SetValue(ToggleTypeProperty, value);
}
public string? GroupName
{
@@ -198,16 +179,6 @@ public class TreeViewItem : AvaloniaTreeItem,
o => o.IconEffectiveVisible,
(o, v) => o.IconEffectiveVisible = v);
internal static readonly DirectProperty<TreeViewItem, bool> IsCheckboxVisibleProperty =
AvaloniaProperty.RegisterDirect<TreeViewItem, bool>(nameof(IsCheckboxVisible),
o => o.IsCheckboxVisible,
(o, v) => o.IsCheckboxVisible = v);
internal static readonly DirectProperty<TreeViewItem, bool> IsCheckboxEnableProperty =
AvaloniaProperty.RegisterDirect<TreeViewItem, bool>(nameof(IsCheckboxEnable),
o => o.IsCheckboxEnable,
(o, v) => o.IsCheckboxEnable = v);
internal static readonly DirectProperty<TreeViewItem, bool> IsDraggingProperty =
AvaloniaProperty.RegisterDirect<TreeViewItem, bool>(nameof(IsDragging),
o => o.IsDragging,
@@ -243,6 +214,9 @@ public class TreeViewItem : AvaloniaTreeItem,
nameof(IsSwitcherRotation),
o => o.IsSwitcherRotation,
(o, v) => o.IsSwitcherRotation = v);
internal static readonly StyledProperty<ItemToggleType> ToggleTypeProperty =
TreeView.ToggleTypeProperty.AddOwner<TreeViewItem>();
private double _titleHeight;
@@ -284,22 +258,6 @@ public class TreeViewItem : AvaloniaTreeItem,
set => SetAndRaise(IconEffectiveVisibleProperty, ref _iconEffectiveVisible, value);
}
private bool _isCheckboxVisible;
internal bool IsCheckboxVisible
{
get => _isCheckboxVisible;
set => SetAndRaise(IsCheckboxVisibleProperty, ref _isCheckboxVisible, value);
}
private bool _isCheckboxEnable;
internal bool IsCheckboxEnable
{
get => _isCheckboxEnable;
set => SetAndRaise(IsCheckboxEnableProperty, ref _isCheckboxEnable, value);
}
private bool _isDragging;
internal bool IsDragging
@@ -357,6 +315,12 @@ public class TreeViewItem : AvaloniaTreeItem,
get => _isSwitcherRotation;
set => SetAndRaise(IsSwitcherRotationProperty, ref _isSwitcherRotation, value);
}
internal ItemToggleType ToggleType
{
get => GetValue(ToggleTypeProperty);
set => SetValue(ToggleTypeProperty, value);
}
internal TreeView? OwnerTreeView { get; set; }
@@ -406,7 +370,6 @@ public class TreeViewItem : AvaloniaTreeItem,
}
SetupSwitcherButtonIconMode();
SetupCheckBoxEnabled();
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
@@ -457,11 +420,6 @@ public class TreeViewItem : AvaloniaTreeItem,
{
CalculateEffectiveBgRect();
}
else if (change.Property == IsEnabledProperty ||
change.Property == IsCheckableProperty)
{
SetupCheckBoxEnabled();
}
else if (change.Property == IsCheckedProperty)
{
// 我们处理某个节点的点击只有 true 或者 false
@@ -585,7 +543,7 @@ public class TreeViewItem : AvaloniaTreeItem,
_switcherButton.IsNodeAnimating = true;
}
var motion = OwnerTreeView.OpenMotion ?? new CollapseMotion(Direction.Top, null, new CubicEaseIn());
var motion = OwnerTreeView.CloseMotion ?? new CollapseMotion(Direction.Top, null, new CubicEaseIn());
motion.Duration = OwnerTreeView.MotionDuration;
MotionInvoker.Invoke(_itemsPresenterMotionActor, motion, null, () =>
@@ -775,19 +733,7 @@ public class TreeViewItem : AvaloniaTreeItem,
}
}
}
private void SetupCheckBoxEnabled()
{
if (!IsEnabled)
{
IsCheckboxEnable = false;
}
else
{
IsCheckboxEnable = IsCheckable;
}
}
private void HandleFrameEntered(object? sender, PointerEventArgs? args)
{
if (NodeHoverMode != TreeItemHoverMode.WholeLine)