mirror of
https://gitee.com/chinware/atomui.git
synced 2024-11-29 18:38:16 +08:00
Complete the inline NavMenu
This commit is contained in:
parent
a21c5a8d7d
commit
e98729e458
@ -187,28 +187,28 @@
|
||||
<!-- </Border> -->
|
||||
<!-- -->
|
||||
<!-- </desktop:ShowCaseItem> -->
|
||||
|
||||
<desktop:ShowCaseItem
|
||||
Title="Top Navigation"
|
||||
Description="Horizontal top navigation menu.">
|
||||
<atom:NavMenu>
|
||||
<atom:NavMenuItem Header="Navigation One" Icon="{atom:IconProvider Kind=MailOutlined}" />
|
||||
<atom:NavMenuItem Header="Navigation Two" Icon="{atom:IconProvider Kind=AppstoreOutlined}" IsEnabled="False"/>
|
||||
<atom:NavMenuItem Header="Navigation Three - Submenu" Icon="{atom:IconProvider Kind=SettingOutlined}">
|
||||
<atom:NavMenuItem Header="Item 1">
|
||||
<atom:NavMenuItem Header="Option 1" />
|
||||
<atom:NavMenuItem Header="Option 2" />
|
||||
</atom:NavMenuItem>
|
||||
|
||||
<atom:NavMenuItem Header="Item 2">
|
||||
<atom:NavMenuItem Header="Option 3" />
|
||||
<atom:NavMenuItem Header="Option 4" />
|
||||
</atom:NavMenuItem>
|
||||
</atom:NavMenuItem>
|
||||
<atom:NavMenuItem Header="Navigation Four"/>
|
||||
</atom:NavMenu>
|
||||
</desktop:ShowCaseItem>
|
||||
|
||||
<!-- -->
|
||||
<!-- <desktop:ShowCaseItem -->
|
||||
<!-- Title="Top Navigation" -->
|
||||
<!-- Description="Horizontal top navigation menu."> -->
|
||||
<!-- <atom:NavMenu> -->
|
||||
<!-- <atom:NavMenuItem Header="Navigation One" Icon="{atom:IconProvider Kind=MailOutlined}" /> -->
|
||||
<!-- <atom:NavMenuItem Header="Navigation Two" Icon="{atom:IconProvider Kind=AppstoreOutlined}" IsEnabled="False"/> -->
|
||||
<!-- <atom:NavMenuItem Header="Navigation Three - Submenu" Icon="{atom:IconProvider Kind=SettingOutlined}"> -->
|
||||
<!-- <atom:NavMenuItem Header="Item 1"> -->
|
||||
<!-- <atom:NavMenuItem Header="Option 1" /> -->
|
||||
<!-- <atom:NavMenuItem Header="Option 2" /> -->
|
||||
<!-- </atom:NavMenuItem> -->
|
||||
<!-- -->
|
||||
<!-- <atom:NavMenuItem Header="Item 2"> -->
|
||||
<!-- <atom:NavMenuItem Header="Option 3" /> -->
|
||||
<!-- <atom:NavMenuItem Header="Option 4" /> -->
|
||||
<!-- </atom:NavMenuItem> -->
|
||||
<!-- </atom:NavMenuItem> -->
|
||||
<!-- <atom:NavMenuItem Header="Navigation Four"/> -->
|
||||
<!-- </atom:NavMenu> -->
|
||||
<!-- </desktop:ShowCaseItem> -->
|
||||
<!-- -->
|
||||
<desktop:ShowCaseItem
|
||||
Title="Vertical menu"
|
||||
Description="Submenus open as pop-ups.">
|
||||
@ -220,7 +220,7 @@
|
||||
<atom:NavMenuItem Header="Option 1" />
|
||||
<atom:NavMenuItem Header="Option 2" />
|
||||
</atom:NavMenuItem>
|
||||
|
||||
|
||||
<atom:NavMenuItem Header="Item 2">
|
||||
<atom:NavMenuItem Header="Option 3" />
|
||||
<atom:NavMenuItem Header="Option 4" />
|
||||
|
@ -411,6 +411,7 @@ namespace AtomUI.Theme.Styling
|
||||
public static readonly TokenResourceKey HorizontalItemHoverBg = new TokenResourceKey("NavMenu.HorizontalItemHoverBg", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey HorizontalItemBorderRadius = new TokenResourceKey("NavMenu.HorizontalItemBorderRadius", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ItemHeight = new TokenResourceKey("NavMenu.ItemHeight", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey InlineItemIndentUnit = new TokenResourceKey("NavMenu.InlineItemIndentUnit", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey CollapsedWidth = new TokenResourceKey("NavMenu.CollapsedWidth", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey MenuPopupBg = new TokenResourceKey("NavMenu.MenuPopupBg", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey HorizontalLineHeight = new TokenResourceKey("NavMenu.HorizontalLineHeight", "AtomUI.Token");
|
||||
|
@ -38,14 +38,14 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
||||
BuildInstanceStyles(item);
|
||||
// 仅仅为了把 Popup 包进来,没有其他什么作用
|
||||
var layoutWrapper = new Panel();
|
||||
var header = BuildMenuItemContent(scope);
|
||||
var header = BuildMenuItemContent(item, scope);
|
||||
BuildExtraItem(layoutWrapper, scope);
|
||||
layoutWrapper.Children.Add(header);
|
||||
return layoutWrapper;
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual Control BuildMenuItemContent(INameScope scope)
|
||||
protected virtual Control BuildMenuItemContent(NavMenuItem navMenuItem, INameScope scope)
|
||||
{
|
||||
var headerFrame = new Border
|
||||
{
|
||||
@ -55,7 +55,13 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
||||
var transitions = new Transitions();
|
||||
transitions.Add(AnimationUtils.CreateTransition<SolidColorBrushTransition>(Border.BackgroundProperty));
|
||||
headerFrame.Transitions = transitions;
|
||||
|
||||
headerFrame.Child = BuildMenuItemInfoGrid(navMenuItem, scope);
|
||||
return headerFrame;
|
||||
}
|
||||
|
||||
protected virtual Grid BuildMenuItemInfoGrid(NavMenuItem navMenuItem, INameScope scope)
|
||||
{
|
||||
var layout = new Grid
|
||||
{
|
||||
Name = MainContainerPart,
|
||||
@ -132,24 +138,21 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
||||
|
||||
inputGestureText.RegisterInNameScope(scope);
|
||||
|
||||
var menuIndicatorIcon = BuildMenuIndicatorIcon();
|
||||
var menuIndicatorIcon = BuildMenuIndicatorIcon(scope);
|
||||
Grid.SetColumn(menuIndicatorIcon, 3);
|
||||
menuIndicatorIcon.RegisterInNameScope(scope);
|
||||
|
||||
layout.Children.Add(iconPresenter);
|
||||
layout.Children.Add(itemTextPresenter);
|
||||
layout.Children.Add(inputGestureText);
|
||||
layout.Children.Add(menuIndicatorIcon);
|
||||
|
||||
headerFrame.Child = layout;
|
||||
return headerFrame;
|
||||
return layout;
|
||||
}
|
||||
|
||||
protected virtual void BuildExtraItem(Panel layout, INameScope scope)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual Control BuildMenuIndicatorIcon()
|
||||
protected virtual Control BuildMenuIndicatorIcon(INameScope scope)
|
||||
{
|
||||
var menuIndicatorIcon = new PathIcon
|
||||
{
|
||||
@ -158,12 +161,23 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Kind = "RightOutlined"
|
||||
};
|
||||
|
||||
|
||||
|
||||
CreateTemplateParentBinding(menuIndicatorIcon, PathIcon.IsEnabledProperty, NavMenuItem.IsEnabledProperty);
|
||||
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, PathIcon.NormalFilledBrushProperty,
|
||||
NavMenuTokenResourceKey.ItemColor);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, PathIcon.SelectedFilledBrushProperty,
|
||||
NavMenuTokenResourceKey.ItemSelectedColor);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, PathIcon.DisabledFilledBrushProperty,
|
||||
NavMenuTokenResourceKey.ItemDisabledColor);
|
||||
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, Layoutable.WidthProperty,
|
||||
NavMenuTokenResourceKey.MenuArrowSize);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(menuIndicatorIcon, Layoutable.HeightProperty,
|
||||
NavMenuTokenResourceKey.MenuArrowSize);
|
||||
|
||||
menuIndicatorIcon.RegisterInNameScope(scope);
|
||||
|
||||
return menuIndicatorIcon;
|
||||
}
|
||||
|
||||
@ -195,31 +209,63 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
||||
}
|
||||
|
||||
// Hover 状态
|
||||
var hoverStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.PointerOver));
|
||||
var hoverStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart).Class(StdPseudoClass.PointerOver));
|
||||
hoverStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemHoverColor);
|
||||
{
|
||||
var borderStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart));
|
||||
borderStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.ItemHoverBg);
|
||||
hoverStyle.Add(borderStyle);
|
||||
}
|
||||
hoverStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.ItemHoverBg);
|
||||
commonStyle.Add(hoverStyle);
|
||||
|
||||
// 选中分两种,一种是有子菜单一种是没有子菜单
|
||||
var hasNoSubMenuStyle = new Style(selector => selector.Nesting().PropertyEquals(NavMenuItem.HasSubMenuProperty, false));
|
||||
{
|
||||
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
||||
{
|
||||
var itemDecoratorStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart));
|
||||
itemDecoratorStyle.Add(Border.BackgroundProperty, NavMenuTokenResourceKey.ItemSelectedBg);
|
||||
itemDecoratorStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemSelectedColor);
|
||||
selectedStyle.Add(itemDecoratorStyle);
|
||||
}
|
||||
hasNoSubMenuStyle.Add(selectedStyle);
|
||||
}
|
||||
commonStyle.Add(hasNoSubMenuStyle);
|
||||
|
||||
var hasSubMenuStyle = new Style(selector => selector.Nesting().PropertyEquals(NavMenuItem.HasSubMenuProperty, true));
|
||||
{
|
||||
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
||||
{
|
||||
var itemDecoratorStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart));
|
||||
itemDecoratorStyle.Add(TemplatedControl.ForegroundProperty, NavMenuTokenResourceKey.ItemSelectedColor);
|
||||
selectedStyle.Add(itemDecoratorStyle);
|
||||
}
|
||||
hasSubMenuStyle.Add(selectedStyle);
|
||||
}
|
||||
commonStyle.Add(hasSubMenuStyle);
|
||||
Add(commonStyle);
|
||||
}
|
||||
|
||||
private void BuildMenuIndicatorStyle()
|
||||
{
|
||||
{
|
||||
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconPart));
|
||||
menuIndicatorStyle.Add(Visual.IsVisibleProperty, true);
|
||||
Add(menuIndicatorStyle);
|
||||
{
|
||||
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconPart));
|
||||
menuIndicatorStyle.Add(Visual.IsVisibleProperty, true);
|
||||
Add(menuIndicatorStyle);
|
||||
}
|
||||
|
||||
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
||||
{
|
||||
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconPart));
|
||||
menuIndicatorStyle.Add(PathIcon.IconModeProperty, IconMode.Selected);
|
||||
selectedStyle.Add(menuIndicatorStyle);
|
||||
}
|
||||
Add(selectedStyle);
|
||||
}
|
||||
var hasSubMenuStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Empty));
|
||||
var hasNoSubMenuStyle = new Style(selector => selector.Nesting().PropertyEquals(NavMenuItem.HasSubMenuProperty, false));
|
||||
{
|
||||
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconPart));
|
||||
menuIndicatorStyle.Add(Visual.IsVisibleProperty, false);
|
||||
hasSubMenuStyle.Add(menuIndicatorStyle);
|
||||
hasNoSubMenuStyle.Add(menuIndicatorStyle);
|
||||
}
|
||||
Add(hasSubMenuStyle);
|
||||
Add(hasNoSubMenuStyle);
|
||||
}
|
||||
|
||||
private void BuildMenuIconStyle()
|
||||
@ -248,13 +294,15 @@ internal class BaseNavMenuItemTheme : BaseControlTheme
|
||||
|
||||
protected override void BuildInstanceStyles(Control control)
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Name(ThemeConstants.ItemIconPart));
|
||||
iconStyle.Add(PathIcon.WidthProperty, NavMenuTokenResourceKey.ItemIconSize);
|
||||
iconStyle.Add(PathIcon.HeightProperty, NavMenuTokenResourceKey.ItemIconSize);
|
||||
iconStyle.Add(PathIcon.NormalFilledBrushProperty, GlobalTokenResourceKey.ColorText);
|
||||
iconStyle.Add(PathIcon.DisabledFilledBrushProperty, NavMenuTokenResourceKey.ItemDisabledColor);
|
||||
iconStyle.Add(PathIcon.SelectedFilledBrushProperty, GlobalTokenResourceKey.ColorPrimary);
|
||||
control.Styles.Add(iconStyle);
|
||||
{
|
||||
var iconStyle = new Style(selector => selector.Name(ThemeConstants.ItemIconPart));
|
||||
iconStyle.Add(PathIcon.WidthProperty, NavMenuTokenResourceKey.ItemIconSize);
|
||||
iconStyle.Add(PathIcon.HeightProperty, NavMenuTokenResourceKey.ItemIconSize);
|
||||
iconStyle.Add(PathIcon.NormalFilledBrushProperty, GlobalTokenResourceKey.ColorText);
|
||||
iconStyle.Add(PathIcon.DisabledFilledBrushProperty, NavMenuTokenResourceKey.ItemDisabledColor);
|
||||
iconStyle.Add(PathIcon.SelectedFilledBrushProperty, GlobalTokenResourceKey.ColorPrimary);
|
||||
control.Styles.Add(iconStyle);
|
||||
}
|
||||
|
||||
var disabledIconStyle = new Style(selector => selector.OfType<PathIcon>().Class(StdPseudoClass.Disabled));
|
||||
disabledIconStyle.Add(PathIcon.IconModeProperty, IconMode.Disabled);
|
||||
|
@ -53,8 +53,9 @@ internal class InlineNavMenuInteractionHandler : INavMenuInteractionHandler
|
||||
{
|
||||
if (NavMenu is NavMenu navMenu)
|
||||
{
|
||||
navMenu.UpdateSelectionFromItem(item);
|
||||
navMenu.ClearSelection();
|
||||
}
|
||||
item?.SelectItemRecursively();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
@ -66,7 +67,7 @@ internal class InlineNavMenuInteractionHandler : INavMenuInteractionHandler
|
||||
item.Open();
|
||||
}
|
||||
|
||||
internal static INavMenuItem? GetMenuItemCore(StyledElement? item)
|
||||
internal static NavMenuItem? GetMenuItemCore(StyledElement? item)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
@ -75,7 +76,7 @@ internal class InlineNavMenuInteractionHandler : INavMenuInteractionHandler
|
||||
return null;
|
||||
}
|
||||
|
||||
if (item is INavMenuItem menuItem)
|
||||
if (item is NavMenuItem menuItem)
|
||||
{
|
||||
return menuItem;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Converters;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Data;
|
||||
@ -30,10 +31,10 @@ internal class InlineNavMenuItemTheme : BaseNavMenuItemTheme
|
||||
return ID;
|
||||
}
|
||||
|
||||
protected override Control BuildMenuIndicatorIcon()
|
||||
protected override Control BuildMenuIndicatorIcon(INameScope scope)
|
||||
{
|
||||
var indicatorIcon = base.BuildMenuIndicatorIcon();
|
||||
var menuIndicatorIconPresenter = new ContentPresenter()
|
||||
var indicatorIcon = base.BuildMenuIndicatorIcon(scope);
|
||||
var menuIndicatorIconPresenter = new Border()
|
||||
{
|
||||
Name = MenuIndicatorIconLayoutPart,
|
||||
Transitions = new Transitions()
|
||||
@ -41,18 +42,20 @@ internal class InlineNavMenuItemTheme : BaseNavMenuItemTheme
|
||||
AnimationUtils.CreateTransition<TransformOperationsTransition>(ContentPresenter.RenderTransformProperty)
|
||||
}
|
||||
};
|
||||
menuIndicatorIconPresenter.Content = indicatorIcon;
|
||||
menuIndicatorIconPresenter.Child = indicatorIcon;
|
||||
menuIndicatorIconPresenter.RegisterInNameScope(scope);
|
||||
return menuIndicatorIconPresenter;
|
||||
}
|
||||
|
||||
protected override Control BuildMenuItemContent(INameScope scope)
|
||||
protected override Control BuildMenuItemContent(NavMenuItem navMenuItem, INameScope scope)
|
||||
{
|
||||
var rootLayout = new StackPanel()
|
||||
{
|
||||
Orientation = Orientation.Vertical
|
||||
};
|
||||
var headerContent = base.BuildMenuItemContent(scope);
|
||||
|
||||
|
||||
var headerContent = base.BuildMenuItemContent(navMenuItem, scope);
|
||||
|
||||
TokenResourceBinder.CreateTokenBinding(headerContent, Control.MarginProperty, NavMenuTokenResourceKey.VerticalItemsPanelSpacing, BindingPriority.Template,
|
||||
(v) =>
|
||||
{
|
||||
@ -84,6 +87,21 @@ internal class InlineNavMenuItemTheme : BaseNavMenuItemTheme
|
||||
return rootLayout;
|
||||
}
|
||||
|
||||
protected override Grid BuildMenuItemInfoGrid(NavMenuItem navMenuItem, INameScope scope)
|
||||
{
|
||||
var infoGrid = base.BuildMenuItemInfoGrid(navMenuItem, scope);
|
||||
var indentConverter = new MarginMultiplierConverter
|
||||
{
|
||||
Left = true,
|
||||
Indent = navMenuItem.InlineItemIndentUnit
|
||||
};
|
||||
CreateTemplateParentBinding(infoGrid, Grid.MarginProperty,
|
||||
NavMenuItem.LevelProperty, BindingMode.OneWay,
|
||||
indentConverter);
|
||||
|
||||
return infoGrid;
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
base.BuildStyles();
|
||||
@ -100,7 +118,7 @@ internal class InlineNavMenuItemTheme : BaseNavMenuItemTheme
|
||||
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconLayoutPart));
|
||||
var transformOptions = new TransformOperations.Builder(1);
|
||||
transformOptions.AppendRotate(MathUtils.Deg2Rad(90));
|
||||
menuIndicatorStyle.Add(ContentPresenter.RenderTransformProperty, transformOptions.Build());
|
||||
menuIndicatorStyle.Add(Border.RenderTransformProperty, transformOptions.Build());
|
||||
menuIndicatorStyle.Add(Visual.IsVisibleProperty, true);
|
||||
Add(menuIndicatorStyle);
|
||||
}
|
||||
@ -109,7 +127,7 @@ internal class InlineNavMenuItemTheme : BaseNavMenuItemTheme
|
||||
var menuIndicatorStyle = new Style(selector => selector.Nesting().Template().Name(MenuIndicatorIconLayoutPart));
|
||||
var transformOptions = new TransformOperations.Builder(1);
|
||||
transformOptions.AppendRotate(MathUtils.Deg2Rad(-90));
|
||||
menuIndicatorStyle.Add(ContentPresenter.RenderTransformProperty, transformOptions.Build());
|
||||
menuIndicatorStyle.Add(Border.RenderTransformProperty, transformOptions.Build());
|
||||
openSubMenuStyle.Add(menuIndicatorStyle);
|
||||
}
|
||||
Add(openSubMenuStyle);
|
||||
@ -121,40 +139,4 @@ internal class InlineNavMenuItemTheme : BaseNavMenuItemTheme
|
||||
}
|
||||
Add(emptySubMenuStyle);
|
||||
}
|
||||
|
||||
// private void BuildAnimationStyle()
|
||||
// {
|
||||
// var closeSubMenuStyle = new Style(selector => selector.Nesting().Not(selector.Nesting().Class(StdPseudoClass.Open)));
|
||||
// {
|
||||
// var layoutTransformStyle =
|
||||
// new Style(selector => selector.Nesting().Template().Name(ChildItemsLayoutTransformPart));
|
||||
// var slideDownInMotionConfig = MotionFactory.BuildSlideUpOutMotion(TimeSpan.FromMilliseconds(300), new QuadraticEaseIn(),
|
||||
// FillMode.Forward);
|
||||
// foreach (var animation in slideDownInMotionConfig.Animations)
|
||||
// {
|
||||
// layoutTransformStyle.Animations.Add(animation);
|
||||
// }
|
||||
// layoutTransformStyle.Add(LayoutTransformControl.RenderTransformOriginProperty, slideDownInMotionConfig.RenderTransformOrigin);
|
||||
// layoutTransformStyle.Add(LayoutTransformControl.IsVisibleProperty, false);
|
||||
// closeSubMenuStyle.Add(layoutTransformStyle);
|
||||
// }
|
||||
// Add(closeSubMenuStyle);
|
||||
//
|
||||
// var openSubMenuStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Open));
|
||||
// {
|
||||
// var layoutTransformStyle =
|
||||
// new Style(selector => selector.Nesting().Template().Name(ChildItemsLayoutTransformPart));
|
||||
// var slideDownInMotionConfig = MotionFactory.BuildSlideUpInMotion(TimeSpan.FromMilliseconds(300), new QuadraticEaseIn(),
|
||||
// FillMode.Forward);
|
||||
// foreach (var animation in slideDownInMotionConfig.Animations)
|
||||
// {
|
||||
// layoutTransformStyle.Animations.Add(animation);
|
||||
// }
|
||||
//
|
||||
// layoutTransformStyle.Add(LayoutTransformControl.RenderTransformOriginProperty, slideDownInMotionConfig.RenderTransformOrigin);
|
||||
// layoutTransformStyle.Add(LayoutTransformControl.IsVisibleProperty, true);
|
||||
// openSubMenuStyle.Add(layoutTransformStyle);
|
||||
// }
|
||||
// Add(openSubMenuStyle);
|
||||
// }
|
||||
}
|
@ -254,8 +254,26 @@ public class NavMenu : NavMenuBase
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateSelectionFromItem(INavMenuItem? item)
|
||||
internal void ClearSelection()
|
||||
{
|
||||
UpdateSelectionFromEventSource(item);
|
||||
foreach (var item in Items)
|
||||
{
|
||||
if (item is NavMenuItem navMenuItem)
|
||||
{
|
||||
ClearSelectionRecursively(navMenuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearSelectionRecursively(NavMenuItem item)
|
||||
{
|
||||
item.IsSelected = false;
|
||||
foreach (var childItem in item.Items)
|
||||
{
|
||||
if (childItem is NavMenuItem navMenuItem)
|
||||
{
|
||||
ClearSelectionRecursively(navMenuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
using System.Windows.Input;
|
||||
using AtomUI.Controls.Utils;
|
||||
using AtomUI.Data;
|
||||
using AtomUI.Icon;
|
||||
using AtomUI.Input;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
@ -84,6 +85,13 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
/// </summary>
|
||||
public static readonly StyledProperty<bool> IsCheckedProperty =
|
||||
AvaloniaProperty.Register<NavMenuItem, bool>(nameof(IsChecked));
|
||||
|
||||
/// <summary>
|
||||
/// Defines the <see cref="Level"/> property.
|
||||
/// </summary>
|
||||
public static readonly DirectProperty<NavMenuItem, int> LevelProperty =
|
||||
AvaloniaProperty.RegisterDirect<NavMenuItem, int>(
|
||||
nameof(Level), o => o.Level);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the command associated with the menu item.
|
||||
@ -171,10 +179,25 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
set => SetValue(IsCheckedProperty, value);
|
||||
}
|
||||
|
||||
private bool _hasSubMenu;
|
||||
/// <summary>
|
||||
/// Gets or sets a value that indicates whether the <see cref="NavMenuItem"/> has a submenu.
|
||||
/// </summary>
|
||||
public bool HasSubMenu => !Classes.Contains(StdPseudoClass.Empty);
|
||||
public bool HasSubMenu
|
||||
{
|
||||
get => _hasSubMenu;
|
||||
set => SetAndRaise(HasSubMenuProperty, ref _hasSubMenu, value);
|
||||
}
|
||||
|
||||
private int _level;
|
||||
/// <summary>
|
||||
/// Gets the level/indentation of the item.
|
||||
/// </summary>
|
||||
public int Level
|
||||
{
|
||||
get => _level;
|
||||
private set => SetAndRaise(LevelProperty, ref _level, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether the <see cref="NavMenuItem"/> is a top-level main menu item.
|
||||
@ -250,6 +273,16 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
o => o.OpenCloseMotionDuration,
|
||||
(o, v) => o.OpenCloseMotionDuration = v);
|
||||
|
||||
internal static readonly DirectProperty<NavMenuItem, bool> HasSubMenuProperty =
|
||||
AvaloniaProperty.RegisterDirect<NavMenuItem, bool>(nameof(HasSubMenu),
|
||||
o => o.HasSubMenu,
|
||||
(o, v) => o.HasSubMenu = v);
|
||||
|
||||
internal static readonly DirectProperty<NavMenuItem, double> InlineItemIndentUnitProperty =
|
||||
AvaloniaProperty.RegisterDirect<NavMenuItem, double>(nameof(InlineItemIndentUnit),
|
||||
o => o.InlineItemIndentUnit,
|
||||
(o, v) => o.InlineItemIndentUnit = v);
|
||||
|
||||
internal double ActiveBarWidth
|
||||
{
|
||||
get => GetValue(ActiveBarWidthProperty);
|
||||
@ -297,7 +330,14 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
set => SetAndRaise(ModeProperty, ref _mode, value);
|
||||
}
|
||||
|
||||
private double _inlineItemIndentUnit;
|
||||
|
||||
internal double InlineItemIndentUnit
|
||||
{
|
||||
get => _inlineItemIndentUnit;
|
||||
set => SetAndRaise(InlineItemIndentUnitProperty, ref _inlineItemIndentUnit, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 公共事件定义
|
||||
@ -428,31 +468,6 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
/// </remarks>
|
||||
public void Open()
|
||||
{
|
||||
if (Mode == NavMenuMode.Inline)
|
||||
{
|
||||
if (_childItemsLayoutTransform is not null)
|
||||
{
|
||||
if (_animating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_animating = true;
|
||||
var slideDownInMotionConfig = MotionFactory.BuildSlideUpInMotion(_openCloseMotionDuration, new QuinticEaseOut(),
|
||||
FillMode.Forward);
|
||||
SetCurrentValue(IsSubMenuOpenProperty, true);
|
||||
_childItemsLayoutTransform.RenderTransformOrigin = slideDownInMotionConfig.RenderTransformOrigin;
|
||||
MotionInvoker.Invoke(_childItemsLayoutTransform, slideDownInMotionConfig, () =>
|
||||
{
|
||||
_childItemsLayoutTransform.SetCurrentValue(IsVisibleProperty, true);
|
||||
}, () =>
|
||||
{
|
||||
_animating = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SetCurrentValue(IsSubMenuOpenProperty, true);
|
||||
}
|
||||
|
||||
@ -464,27 +479,6 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
/// </remarks>
|
||||
public void Close()
|
||||
{
|
||||
if (Mode == NavMenuMode.Inline)
|
||||
{
|
||||
if (_childItemsLayoutTransform is not null)
|
||||
{
|
||||
if (_animating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_animating = true;
|
||||
SetCurrentValue(IsSubMenuOpenProperty, false);
|
||||
var slideDownOutMotionConfig = MotionFactory.BuildSlideUpOutMotion(_openCloseMotionDuration, new QuinticEaseOut(),
|
||||
FillMode.Forward);
|
||||
MotionInvoker.Invoke(_childItemsLayoutTransform, slideDownOutMotionConfig, null, () =>
|
||||
{
|
||||
_childItemsLayoutTransform.SetCurrentValue(IsVisibleProperty, false);
|
||||
_animating = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
SetCurrentValue(IsSubMenuOpenProperty, false);
|
||||
}
|
||||
|
||||
@ -528,6 +522,8 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
}
|
||||
|
||||
base.OnAttachedToLogicalTree(e);
|
||||
|
||||
Level = CalculateDistanceFromLogicalParent<NavMenu>(this) - 1;
|
||||
|
||||
(var command, var parameter) = (Command, CommandParameter);
|
||||
if (command is not null)
|
||||
@ -545,6 +541,7 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
}
|
||||
|
||||
_isEmbeddedInMenu = parent?.FindLogicalAncestorOfType<INavMenu>(true) != null;
|
||||
TokenResourceBinder.CreateTokenBinding(this, InlineItemIndentUnitProperty, NavMenuTokenResourceKey.InlineItemIndentUnit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -590,7 +587,10 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
protected override void OnGotFocus(GotFocusEventArgs e)
|
||||
{
|
||||
base.OnGotFocus(e);
|
||||
e.Handled = UpdateSelectionFromEventSource(e.Source, true);
|
||||
if (Mode != NavMenuMode.Inline || !HasSubMenu)
|
||||
{
|
||||
e.Handled = UpdateSelectionFromEventSource(e.Source, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -620,15 +620,19 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
protected virtual void OnSubmenuOpened(RoutedEventArgs e)
|
||||
{
|
||||
var menuItem = e.Source as NavMenuItem;
|
||||
|
||||
|
||||
if (menuItem != null && menuItem.Parent == this)
|
||||
{
|
||||
foreach (var child in ((INavMenuItem)this).SubItems)
|
||||
// TODO 我们在这里对模式做一个区分, Inline 暂时不互斥关闭,后面有时间看是否加一个互斥的标记
|
||||
if (Mode != NavMenuMode.Inline)
|
||||
{
|
||||
if (child != menuItem && child.IsSubMenuOpen)
|
||||
foreach (var child in ((INavMenuItem)this).SubItems)
|
||||
{
|
||||
child.IsSubMenuOpen = false;
|
||||
}
|
||||
if (child != menuItem && child.IsSubMenuOpen)
|
||||
{
|
||||
child.IsSubMenuOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -819,6 +823,9 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
} else if (change.Property == ModeProperty)
|
||||
{
|
||||
SetupItemContainerTheme(true);
|
||||
} else if (change.Property == ItemCountProperty)
|
||||
{
|
||||
HasSubMenu = ItemCount > 0;
|
||||
}
|
||||
|
||||
if (change.Property == BoundsProperty ||
|
||||
@ -917,11 +924,23 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
private void IsSelectedChanged(AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
var parentMenu = Parent as NavMenu;
|
||||
|
||||
if ((bool)e.NewValue! && (parentMenu is null || parentMenu.IsOpen))
|
||||
var isSelected = e.GetNewValue<bool>();
|
||||
if (isSelected && (parentMenu is null || parentMenu.IsOpen))
|
||||
{
|
||||
Focus();
|
||||
}
|
||||
|
||||
if (Icon is not null && Icon is PathIcon menuIcon)
|
||||
{
|
||||
if (isSelected)
|
||||
{
|
||||
menuIcon.SetValue(PathIcon.IconModeProperty, IconMode.Selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
menuIcon.SetValue(PathIcon.IconModeProperty, IconMode.Normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -932,22 +951,87 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
{
|
||||
var value = (bool)e.NewValue!;
|
||||
|
||||
if (value)
|
||||
if (Mode == NavMenuMode.Inline)
|
||||
{
|
||||
foreach (var item in ItemsView.OfType<NavMenuItem>())
|
||||
// 在这里我们有一个动画的效果
|
||||
if (value)
|
||||
{
|
||||
item.TryUpdateCanExecute();
|
||||
}
|
||||
foreach (var item in ItemsView.OfType<NavMenuItem>())
|
||||
{
|
||||
item.TryUpdateCanExecute();
|
||||
}
|
||||
|
||||
RaiseEvent(new RoutedEventArgs(SubmenuOpenedEvent));
|
||||
SetCurrentValue(IsSelectedProperty, true);
|
||||
PseudoClasses.Add(StdPseudoClass.Open);
|
||||
RaiseEvent(new RoutedEventArgs(SubmenuOpenedEvent));
|
||||
PseudoClasses.Add(StdPseudoClass.Open);
|
||||
OpenInlineItem();
|
||||
} else
|
||||
{
|
||||
PseudoClasses.Remove(StdPseudoClass.Open);
|
||||
CloseInlineItem();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseSubmenus();
|
||||
SelectedIndex = -1;
|
||||
PseudoClasses.Remove(StdPseudoClass.Open);
|
||||
if (value)
|
||||
{
|
||||
foreach (var item in ItemsView.OfType<NavMenuItem>())
|
||||
{
|
||||
item.TryUpdateCanExecute();
|
||||
}
|
||||
RaiseEvent(new RoutedEventArgs(SubmenuOpenedEvent));
|
||||
SetCurrentValue(IsSelectedProperty, true);
|
||||
PseudoClasses.Add(StdPseudoClass.Open);
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseSubmenus();
|
||||
SelectedIndex = -1;
|
||||
PseudoClasses.Remove(StdPseudoClass.Open);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenInlineItem()
|
||||
{
|
||||
if (_childItemsLayoutTransform is not null)
|
||||
{
|
||||
if (_animating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_animating = true;
|
||||
var slideDownInMotionConfig = MotionFactory.BuildSlideUpInMotion(_openCloseMotionDuration, new QuinticEaseOut(),
|
||||
FillMode.Forward);
|
||||
_childItemsLayoutTransform.RenderTransformOrigin = slideDownInMotionConfig.RenderTransformOrigin;
|
||||
MotionInvoker.Invoke(_childItemsLayoutTransform, slideDownInMotionConfig, () =>
|
||||
{
|
||||
_childItemsLayoutTransform.SetCurrentValue(IsVisibleProperty, true);
|
||||
}, () =>
|
||||
{
|
||||
_animating = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseInlineItem()
|
||||
{
|
||||
if (_childItemsLayoutTransform is not null)
|
||||
{
|
||||
if (_animating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_animating = true;
|
||||
SetCurrentValue(IsSubMenuOpenProperty, false);
|
||||
var slideDownOutMotionConfig = MotionFactory.BuildSlideUpOutMotion(_openCloseMotionDuration, new QuinticEaseOut(),
|
||||
FillMode.Forward);
|
||||
MotionInvoker.Invoke(_childItemsLayoutTransform, slideDownOutMotionConfig, null, () =>
|
||||
{
|
||||
_childItemsLayoutTransform.SetCurrentValue(IsVisibleProperty, false);
|
||||
_animating = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1038,4 +1122,29 @@ public class NavMenuItem : HeaderedSelectingItemsControl,
|
||||
BindUtils.RelayBind(this, ModeProperty, navMenuItem, ModeProperty);
|
||||
}
|
||||
}
|
||||
|
||||
internal void SelectItemRecursively()
|
||||
{
|
||||
IsSelected = true;
|
||||
if (!IsTopLevel)
|
||||
{
|
||||
if (Parent is NavMenuItem parent)
|
||||
{
|
||||
parent.SelectItemRecursively();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int CalculateDistanceFromLogicalParent<T>(ILogical? logical, int @default = -1) where T : class
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
while (logical != null && !(logical is T))
|
||||
{
|
||||
++result;
|
||||
logical = logical.LogicalParent;
|
||||
}
|
||||
|
||||
return logical != null ? result : @default;
|
||||
}
|
||||
}
|
@ -215,6 +215,11 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
/// </summary>
|
||||
public double ItemHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内联菜单项的缩进单位
|
||||
/// </summary>
|
||||
public double InlineItemIndentUnit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收起后的宽度
|
||||
/// </summary>
|
||||
@ -446,5 +451,7 @@ internal class NavMenuToken : AbstractControlDesignToken
|
||||
MenuPopupContentPadding = new Thickness(_globalToken.PaddingXXS, MenuPopupBorderRadius.TopLeft / 2);
|
||||
MenuPopupBoxShadows = _globalToken.BoxShadowsSecondary;
|
||||
VerticalItemsPanelSpacing = _globalToken.MarginXXS;
|
||||
|
||||
InlineItemIndentUnit = ItemHeight / 2;
|
||||
}
|
||||
}
|
@ -206,6 +206,14 @@ public sealed class PathIcon : Control, ICustomHitTest
|
||||
BuildSourceRenderData();
|
||||
}
|
||||
}
|
||||
else if (change.Property == IsEnabledProperty)
|
||||
{
|
||||
// TODO 这个地方需要优化一点,是否需要保存老的,当状态为 Enabled 的时候进行还原
|
||||
if (!IsEnabled)
|
||||
{
|
||||
IconMode = IconMode.Disabled;
|
||||
}
|
||||
}
|
||||
else if (change.Property == NormalFilledBrushProperty ||
|
||||
change.Property == ActiveFilledBrushProperty ||
|
||||
change.Property == SelectedFilledBrushProperty ||
|
||||
|
Loading…
Reference in New Issue
Block a user