diff --git a/src/AtomUI.Controls.DataGrid/Utils/Converters/DataGridHeaderIndicatorLayoutMarginsConverter.cs b/src/AtomUI.Controls.DataGrid/Utils/Converters/DataGridHeaderIndicatorLayoutMarginsConverter.cs
deleted file mode 100644
index 377769d92..000000000
--- a/src/AtomUI.Controls.DataGrid/Utils/Converters/DataGridHeaderIndicatorLayoutMarginsConverter.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Globalization;
-using Avalonia;
-using Avalonia.Data.Converters;
-
-namespace AtomUI.Controls.Converters;
-
-internal class DataGridHeaderIndicatorLayoutMarginsConverter : IValueConverter
-{
- public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
- {
- if (value is Thickness paddings)
- {
- return new Thickness(0, 0, paddings.Right, 0);
- }
- return value;
- }
-
- public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
- {
- throw new NotImplementedException();
- }
-}
\ No newline at end of file
diff --git a/src/AtomUI.Controls/NavMenu/DefaultNavMenuInteractionHandler.cs b/src/AtomUI.Controls/NavMenu/DefaultNavMenuInteractionHandler.cs
index 9520534b8..4ec2b96c8 100644
--- a/src/AtomUI.Controls/NavMenu/DefaultNavMenuInteractionHandler.cs
+++ b/src/AtomUI.Controls/NavMenu/DefaultNavMenuInteractionHandler.cs
@@ -140,15 +140,13 @@ internal class DefaultNavMenuInteractionHandler : INavMenuInteractionHandler
// 判断当前选中的是不是自己
if (!ReferenceEquals(LatestSelectedItem, navMenuItem))
{
+ var navMenu = Menu as NavMenu;
if (LatestSelectedItem != null)
{
var ancestorInfo = HasCommonAncestor(LatestSelectedItem, navMenuItem);
if (!ancestorInfo.Item1)
{
- if (Menu is NavMenu navMenu)
- {
- navMenu.ClearSelection();
- }
+ navMenu?.ClearSelection();
}
else
{
@@ -160,6 +158,7 @@ internal class DefaultNavMenuInteractionHandler : INavMenuInteractionHandler
}
navMenuItem.SelectItemRecursively();
LatestSelectedItem = navMenuItem;
+ navMenu?.RaiseNavMenuItemSelected(navMenuItem);
}
}
}
@@ -219,7 +218,7 @@ internal class DefaultNavMenuInteractionHandler : INavMenuInteractionHandler
}
_currentPressedIsValid = false;
- if (e.InitialPressMouseButton == MouseButton.Left && item.HasSubMenu == false)
+ if (e.InitialPressMouseButton == MouseButton.Left)
{
Click(item);
e.Handled = true;
@@ -264,14 +263,25 @@ internal class DefaultNavMenuInteractionHandler : INavMenuInteractionHandler
{
if (e.Source is ILogical control && !Menu.IsLogicalAncestorOf(control))
{
- Menu?.Close();
+ CloseAllTopLevelMenuItems();
}
}
}
protected virtual void WindowDeactivated(object? sender, EventArgs e)
{
- Menu?.Close();
+ CloseAllTopLevelMenuItems();
+ }
+
+ private void CloseAllTopLevelMenuItems()
+ {
+ if (Menu != null)
+ {
+ foreach (var i in Menu.SubItems)
+ {
+ i.Close();
+ }
+ }
}
internal static NavMenuItem? GetMenuItem(StyledElement? item) => (NavMenuItem?)GetMenuItemCore(item);
@@ -352,12 +362,14 @@ internal class DefaultNavMenuInteractionHandler : INavMenuInteractionHandler
internal void Click(INavMenuItem item)
{
item.RaiseClick();
- var navMenu = FindNavMenu(item);
- navMenu?.RaiseNavMenuItemClick(item);
- if (!item.StaysOpenOnClick)
+ if (Menu is NavMenu navMenu)
{
- var topLevelItem = FindTopLevelMenuItem(item);
- topLevelItem?.Close();
+ navMenu.RaiseNavMenuItemClick(item);
+ if (!item.HasSubMenu && !item.StaysOpenOnClick)
+ {
+ var topLevelItem = FindTopLevelMenuItem(item);
+ topLevelItem?.Close();
+ }
}
}
diff --git a/src/AtomUI.Controls/NavMenu/INavMenu.cs b/src/AtomUI.Controls/NavMenu/INavMenu.cs
index d97d9217f..344cc67f9 100644
--- a/src/AtomUI.Controls/NavMenu/INavMenu.cs
+++ b/src/AtomUI.Controls/NavMenu/INavMenu.cs
@@ -1,10 +1,15 @@
-using Avalonia.Input;
+using AtomUI.Controls.Primitives;
using Avalonia.Rendering;
namespace AtomUI.Controls;
-internal interface INavMenu : INavMenuElement, IInputElement
+internal interface INavMenu : INavMenuElement
{
+ ///
+ /// Gets or sets the currently selected submenu item.
+ ///
+ INavMenuItem? SelectedItem { get; }
+
///
/// Gets the menu interaction handler.
///
@@ -19,4 +24,14 @@ internal interface INavMenu : INavMenuElement, IInputElement
/// Gets the root of the visual tree, if the control is attached to a visual tree.
///
IRenderRoot? VisualRoot { get; }
+
+ ///
+ /// List of paths opened by default
+ ///
+ IList? DefaultOpenPaths { get; set; }
+
+ ///
+ /// Default selected path
+ ///
+ TreeNodePath? DefaultSelectedPath { get; set; }
}
\ No newline at end of file
diff --git a/src/AtomUI.Controls/NavMenu/INavMenuElement.cs b/src/AtomUI.Controls/NavMenu/INavMenuElement.cs
index 5a441a7b1..89997c34e 100644
--- a/src/AtomUI.Controls/NavMenu/INavMenuElement.cs
+++ b/src/AtomUI.Controls/NavMenu/INavMenuElement.cs
@@ -5,11 +5,6 @@ namespace AtomUI.Controls;
public interface INavMenuElement : IInputElement, ILogical
{
- ///
- /// Gets or sets the currently selected submenu item.
- ///
- INavMenuItem? SelectedItem { get; set; }
-
///
/// Gets the submenu items.
///
diff --git a/src/AtomUI.Controls/NavMenu/INavMenuItem.cs b/src/AtomUI.Controls/NavMenu/INavMenuItem.cs
index 8f7ffc0d5..d6e434ac0 100644
--- a/src/AtomUI.Controls/NavMenu/INavMenuItem.cs
+++ b/src/AtomUI.Controls/NavMenu/INavMenuItem.cs
@@ -2,6 +2,11 @@
public interface INavMenuItem : INavMenuElement
{
+ ///
+ /// Gets or sets the currently selected submenu item.
+ ///
+ INavMenuItem? SelectedItem { get; set; }
+
///
/// Gets or sets a value that item key.
///
diff --git a/src/AtomUI.Controls/NavMenu/InlineNavMenuInteractionHandler.cs b/src/AtomUI.Controls/NavMenu/InlineNavMenuInteractionHandler.cs
index 9b571da7a..c47869fc1 100644
--- a/src/AtomUI.Controls/NavMenu/InlineNavMenuInteractionHandler.cs
+++ b/src/AtomUI.Controls/NavMenu/InlineNavMenuInteractionHandler.cs
@@ -9,7 +9,7 @@ using NavMenuControl = NavMenu;
internal class InlineNavMenuInteractionHandler : INavMenuInteractionHandler
{
- internal INavMenu? NavMenu { get; private set; }
+ internal INavMenu? Menu { get; private set; }
public void Attach(NavMenu navMenu) => AttachCore(navMenu);
public void Detach(NavMenu navMenu) => DetachCore(navMenu);
@@ -19,24 +19,24 @@ internal class InlineNavMenuInteractionHandler : INavMenuInteractionHandler
internal void AttachCore(INavMenu navMenu)
{
- if (NavMenu != null)
+ if (Menu != null)
{
throw new NotSupportedException("InlineNavMenuInteractionHandler is already attached.");
}
- NavMenu = navMenu;
- NavMenu.PointerPressed += PointerPressed;
- NavMenu.PointerReleased += PointerReleased;
+ Menu = navMenu;
+ Menu.PointerPressed += PointerPressed;
+ Menu.PointerReleased += PointerReleased;
}
internal void DetachCore(INavMenu navMenu)
{
- if (NavMenu != navMenu)
+ if (Menu != navMenu)
{
throw new NotSupportedException("InlineNavMenuInteractionHandler is not attached to the navMenu.");
}
- NavMenu.PointerPressed -= PointerPressed;
- NavMenu.PointerReleased -= PointerReleased;
- NavMenu = null;
+ Menu.PointerPressed -= PointerPressed;
+ Menu.PointerReleased -= PointerReleased;
+ Menu = null;
}
protected virtual void PointerPressed(object? sender, PointerPressedEventArgs e)
@@ -75,15 +75,13 @@ internal class InlineNavMenuInteractionHandler : INavMenuInteractionHandler
// 判断当前选中的是不是自己
if (!ReferenceEquals(LatestSelectedItem, navMenuItem))
{
+ var navMenu = Menu as NavMenu;
if (LatestSelectedItem != null)
{
var ancestorInfo = HasCommonAncestor(LatestSelectedItem, navMenuItem);
if (!ancestorInfo.Item1)
{
- if (NavMenu is NavMenu navMenu)
- {
- navMenu.ClearSelection();
- }
+ navMenu?.ClearSelection();
}
else
{
@@ -96,6 +94,7 @@ internal class InlineNavMenuInteractionHandler : INavMenuInteractionHandler
navMenuItem.SelectItemRecursively();
LatestSelectedItem = navMenuItem;
+ navMenu?.RaiseNavMenuItemSelected(navMenuItem);
}
}
}
@@ -156,7 +155,7 @@ internal class InlineNavMenuInteractionHandler : INavMenuInteractionHandler
_currentPressedIsValid = false;
- if (e.InitialPressMouseButton == MouseButton.Left && !item.HasSubMenu)
+ if (e.InitialPressMouseButton == MouseButton.Left)
{
Click(item);
e.Handled = true;
@@ -166,8 +165,10 @@ internal class InlineNavMenuInteractionHandler : INavMenuInteractionHandler
internal void Click(INavMenuItem item)
{
item.RaiseClick();
- var navMenu = FindNavMenu(item);
- navMenu?.RaiseNavMenuItemClick(item);
+ if (Menu is NavMenu navMenu)
+ {
+ navMenu.RaiseNavMenuItemClick(item);
+ }
}
internal void Open(INavMenuItem item)
@@ -192,21 +193,4 @@ internal class InlineNavMenuInteractionHandler : INavMenuInteractionHandler
item = item.Parent;
}
}
-
- private static NavMenu? FindNavMenu(INavMenuItem item)
- {
- var current = (INavMenuElement?)item;
- NavMenu? result = null;
-
- while (current != null && !(current is NavMenu))
- {
- current = (current as INavMenuItem)?.Parent;
- }
-
- if (current is NavMenu navMenu)
- {
- result = navMenu;
- }
- return result;
- }
}
\ No newline at end of file
diff --git a/src/AtomUI.Controls/NavMenu/NavMenu.cs b/src/AtomUI.Controls/NavMenu/NavMenu.cs
index c5f9741b1..352ec899c 100644
--- a/src/AtomUI.Controls/NavMenu/NavMenu.cs
+++ b/src/AtomUI.Controls/NavMenu/NavMenu.cs
@@ -3,7 +3,6 @@ using System.Reactive.Disposables;
using AtomUI.Controls.Primitives;
using AtomUI.Controls.Themes;
using AtomUI.Data;
-using AtomUI.Exceptions;
using AtomUI.Theme;
using AtomUI.Theme.Data;
using AtomUI.Theme.Styling;
@@ -28,60 +27,62 @@ using Avalonia.VisualTree;
namespace AtomUI.Controls;
-public class NavMenuItemClickEventArgs : RoutedEventArgs
-{
- public NavMenuItemClickEventArgs(RoutedEvent routedEvent, INavMenuItem navMenuItem)
- : base(routedEvent)
- {
- NavMenuItem = navMenuItem;
- }
-
- public INavMenuItem NavMenuItem { get; }
-}
-
[PseudoClasses(
NavMenuPseudoClass.InlineMode,
NavMenuPseudoClass.HorizontalMode,
NavMenuPseudoClass.VerticalMode,
NavMenuPseudoClass.DarkStyle,
NavMenuPseudoClass.LightStyle)]
-public class NavMenu : SelectingItemsControl,
- IFocusScope,
+public class NavMenu : ItemsControl,
+ IFocusScope,
INavMenu,
IMotionAwareControl,
IControlSharedTokenResourcesHost
{
#region 公共属性定义
- public static readonly DirectProperty?> DefaultOpenPathsProperty =
- AvaloniaProperty.RegisterDirect?>(
- nameof(DefaultOpenPaths),
- o => o.DefaultOpenPaths,
- (o, v) => o.DefaultOpenPaths = v);
-
+ public static readonly DirectProperty SelectedItemProperty =
+ AvaloniaProperty.RegisterDirect(
+ nameof(SelectedItem),
+ o => o.SelectedItem);
+
public static readonly DirectProperty DefaultSelectedPathProperty =
AvaloniaProperty.RegisterDirect(
nameof(DefaultSelectedPath),
o => o.DefaultSelectedPath,
(o, v) => o.DefaultSelectedPath = v);
-
+
public static readonly DirectProperty IsOpenProperty =
AvaloniaProperty.RegisterDirect(
nameof(IsOpen),
o => o.IsOpen);
-
+
public static readonly StyledProperty IsMotionEnabledProperty =
MotionAwareControlProperty.IsMotionEnabledProperty.AddOwner();
-
+
public static readonly StyledProperty IsAccordionModeProperty =
AvaloniaProperty.Register(nameof(IsAccordionMode), false);
-
+
public static readonly StyledProperty ModeProperty =
AvaloniaProperty.Register(nameof(Mode), NavMenuMode.Horizontal);
public static readonly StyledProperty IsDarkStyleProperty =
AvaloniaProperty.Register(nameof(IsDarkStyle), false);
+ public static readonly DirectProperty?> DefaultOpenPathsProperty =
+ AvaloniaProperty.RegisterDirect?>(
+ nameof(DefaultOpenPaths),
+ o => o.DefaultOpenPaths,
+ (o, v) => o.DefaultOpenPaths = v);
+
+ public INavMenuItem? _selectedItem;
+
+ public INavMenuItem? SelectedItem
+ {
+ get => _selectedItem;
+ private set => SetAndRaise(SelectedItemProperty, ref _selectedItem, value);
+ }
+
private IList? _defaultOpenPaths;
public IList? DefaultOpenPaths
@@ -135,9 +136,10 @@ public class NavMenu : SelectingItemsControl,
#region 公共事件定义
public static readonly RoutedEvent NavMenuItemClickEvent =
- RoutedEvent.Register(
- nameof(NavMenuItemClick),
- RoutingStrategies.Bubble);
+ RoutedEvent.Register(nameof(NavMenuItemClick), RoutingStrategies.Bubble);
+
+ public static readonly RoutedEvent NavMenuItemSelectedEvent =
+ RoutedEvent.Register(nameof(NavMenuItemSelected), RoutingStrategies.Bubble);
public static readonly RoutedEvent OpenedEvent =
RoutedEvent.Register(nameof(Opened), RoutingStrategies.Bubble);
@@ -151,6 +153,12 @@ public class NavMenu : SelectingItemsControl,
remove => RemoveHandler(NavMenuItemClickEvent, value);
}
+ public event EventHandler? NavMenuItemSelected
+ {
+ add => AddHandler(NavMenuItemSelectedEvent, value);
+ remove => RemoveHandler(NavMenuItemSelectedEvent, value);
+ }
+
public event EventHandler? Opened
{
add => AddHandler(OpenedEvent, value);
@@ -185,17 +193,6 @@ public class NavMenu : SelectingItemsControl,
IRenderRoot? INavMenu.VisualRoot => VisualRoot;
- INavMenuItem? INavMenuElement.SelectedItem
- {
- get
- {
- var index = SelectedIndex;
- return (index != -1) ? (INavMenuItem?)ContainerFromIndex(index) : null;
- }
-
- set => SelectedIndex = value is Control c ? IndexFromContainer(c) : -1;
- }
-
IEnumerable INavMenuElement.SubItems => LogicalChildren.OfType();
///
@@ -217,7 +214,6 @@ public class NavMenu : SelectingItemsControl,
KeyboardNavigationMode.Once);
AutomationProperties.AccessibilityViewProperty.OverrideDefaultValue(AccessibilityView.Control);
AutomationProperties.ControlTypeOverrideProperty.OverrideDefaultValue(AutomationControlType.Menu);
- AutoScrollToSelectedItemProperty.OverrideDefaultValue(false);
NavMenuItem.SubmenuOpenedEvent.AddClassHandler((x, e) => x.OnSubmenuOpened(e));
}
@@ -240,7 +236,7 @@ public class NavMenu : SelectingItemsControl,
}
IsOpen = false;
- SelectedIndex = -1;
+ SelectedItem = null;
RaiseEvent(new RoutedEventArgs
{
@@ -286,15 +282,6 @@ public class NavMenu : SelectingItemsControl,
}
IsOpen = true;
}
-
- private void ValidateSelectionMode()
- {
- if (SelectionMode.HasFlag(SelectionMode.Multiple))
- {
- throw new InvalidPropertyValueException(SelectionModeProperty.Name, SelectionMode.Multiple,
- $"The value '{SelectionMode.Multiple}' is invalid for the '{SelectionModeProperty.Name}' property in NavMenuItem.");
- }
- }
private void HandleItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
@@ -331,10 +318,6 @@ public class NavMenu : SelectingItemsControl,
}
}
}
- else if (change.Property == SelectionModeProperty)
- {
- ValidateSelectionMode();
- }
if (change.Property == IsDarkStyleProperty ||
change.Property == ModeProperty)
{
@@ -660,6 +643,11 @@ public class NavMenu : SelectingItemsControl,
RaiseEvent(new NavMenuItemClickEventArgs(NavMenuItemClickEvent, navMenuItem));
}
+ internal void RaiseNavMenuItemSelected(INavMenuItem navMenuItem)
+ {
+ RaiseEvent(new NavMenuItemSelectedEventArgs(NavMenuItemSelectedEvent, navMenuItem));
+ }
+
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
diff --git a/src/AtomUI.Controls/NavMenu/NavMenuEventArgs.cs b/src/AtomUI.Controls/NavMenu/NavMenuEventArgs.cs
new file mode 100644
index 000000000..46e85c512
--- /dev/null
+++ b/src/AtomUI.Controls/NavMenu/NavMenuEventArgs.cs
@@ -0,0 +1,25 @@
+using Avalonia.Interactivity;
+
+namespace AtomUI.Controls;
+
+public class NavMenuItemClickEventArgs : RoutedEventArgs
+{
+ public NavMenuItemClickEventArgs(RoutedEvent routedEvent, INavMenuItem navMenuItem)
+ : base(routedEvent)
+ {
+ NavMenuItem = navMenuItem;
+ }
+
+ public INavMenuItem NavMenuItem { get; }
+}
+
+public class NavMenuItemSelectedEventArgs : RoutedEventArgs
+{
+ public NavMenuItemSelectedEventArgs(RoutedEvent routedEvent, INavMenuItem navMenuItem)
+ : base(routedEvent)
+ {
+ NavMenuItem = navMenuItem;
+ }
+
+ public INavMenuItem NavMenuItem { get; }
+}
\ No newline at end of file
diff --git a/src/AtomUI.Controls/NavMenu/NavMenuItem.cs b/src/AtomUI.Controls/NavMenu/NavMenuItem.cs
index 2a27e975f..acffc2b1c 100644
--- a/src/AtomUI.Controls/NavMenu/NavMenuItem.cs
+++ b/src/AtomUI.Controls/NavMenu/NavMenuItem.cs
@@ -191,12 +191,12 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
protected override bool IsEnabledCore => base.IsEnabledCore && _commandCanExecute;
- INavMenuItem? INavMenuElement.SelectedItem
+ INavMenuItem? INavMenuItem.SelectedItem
{
get
{
var index = SelectedIndex;
- return (index != -1) ? (INavMenuItem?)ContainerFromIndex(index) : null;
+ return index != -1 ? (INavMenuItem?)ContainerFromIndex(index) : null;
}
set => SelectedIndex = value is Control c ? IndexFromContainer(c) : -1;