mirror of
https://gitee.com/chinware/atomui.git
synced 2024-12-02 03:47:52 +08:00
完成 TabStrip 下拉菜单
当Tab菜单过多的时候显示一个下拉菜单
This commit is contained in:
parent
5dbd7e45b5
commit
3ef2587f39
@ -210,9 +210,11 @@ public class TabScrollViewer : ScrollViewer
|
||||
var right = Math.Floor(itemBounds.Right - Offset.X);
|
||||
if (TabStripPlacement == Dock.Top || TabStripPlacement == Dock.Bottom) {
|
||||
if (left < 0 || right > Viewport.Width) {
|
||||
var menuItem = new MenuItem()
|
||||
var menuItem = new TabStripMenuItem()
|
||||
{
|
||||
Header = tabStripItem.Content,
|
||||
TabStripItem = tabStripItem,
|
||||
IsClosable = tabStripItem.IsClosable
|
||||
};
|
||||
menuItem.Click += HandleMenuItemClicked;
|
||||
_menuFlyout.Items.Add(menuItem);
|
||||
@ -230,14 +232,16 @@ public class TabScrollViewer : ScrollViewer
|
||||
private void HandleMenuItemClicked(object? sender, RoutedEventArgs args)
|
||||
{
|
||||
if (TabStrip is not null) {
|
||||
TabStrip.BringIntoView();
|
||||
Dispatcher.UIThread.Post(sender =>
|
||||
{
|
||||
var item = TabStrip.Items[5];
|
||||
if (item is TabStripItem tabStripItem) {
|
||||
tabStripItem.BringIntoView();
|
||||
if (sender is TabStripMenuItem tabStripMenuItem) {
|
||||
var tabStripItem = tabStripMenuItem.TabStripItem;
|
||||
if (tabStripItem is not null) {
|
||||
tabStripItem.BringIntoView();
|
||||
TabStrip.SelectedItem = tabStripItem;
|
||||
}
|
||||
}
|
||||
}, sender);
|
||||
}, sender);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,8 @@ public class TabStripItem : AvaloniaTabStripItem, IControlCustomStyle, ICustomHi
|
||||
public static readonly StyledProperty<PathIcon?> CloseIconProperty =
|
||||
AvaloniaProperty.Register<TabStripItem, PathIcon?>(nameof(CloseIcon));
|
||||
|
||||
public static readonly StyledProperty<bool> ClosableProperty =
|
||||
AvaloniaProperty.Register<TabStripItem, bool>(nameof(Closable));
|
||||
public static readonly StyledProperty<bool> IsClosableProperty =
|
||||
AvaloniaProperty.Register<TabStripItem, bool>(nameof(IsClosable));
|
||||
|
||||
public static readonly DirectProperty<TabStripItem, Dock?> TabStripPlacementProperty =
|
||||
AvaloniaProperty.RegisterDirect<TabStripItem, Dock?>(nameof(TabStripPlacement), o => o.TabStripPlacement);
|
||||
@ -57,10 +57,10 @@ public class TabStripItem : AvaloniaTabStripItem, IControlCustomStyle, ICustomHi
|
||||
set => SetValue(CloseIconProperty, value);
|
||||
}
|
||||
|
||||
public bool Closable
|
||||
public bool IsClosable
|
||||
{
|
||||
get => GetValue(ClosableProperty);
|
||||
set => SetValue(ClosableProperty, value);
|
||||
get => GetValue(IsClosableProperty);
|
||||
set => SetValue(IsClosableProperty, value);
|
||||
}
|
||||
|
||||
private Dock? _tabStripPlacement;
|
||||
|
@ -1,6 +1,56 @@
|
||||
namespace AtomUI.Controls;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.LogicalTree;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
internal class TabStripMenuItem : MenuItem
|
||||
{
|
||||
#region 公共属性
|
||||
|
||||
public static readonly DirectProperty<TabStripMenuItem, bool> IsClosableProperty =
|
||||
AvaloniaProperty.RegisterDirect<TabStripMenuItem, bool>(nameof(IsClosable),
|
||||
o => o.IsClosable,
|
||||
(o, v) => o.IsClosable = v);
|
||||
|
||||
public static readonly RoutedEvent<RoutedEventArgs> CloseTabEvent =
|
||||
RoutedEvent.Register<Button, RoutedEventArgs>(nameof(CloseTab), RoutingStrategies.Bubble);
|
||||
|
||||
private bool _isClosable = false;
|
||||
public bool IsClosable
|
||||
{
|
||||
get => _isClosable;
|
||||
set => SetAndRaise(IsClosableProperty, ref _isClosable, value);
|
||||
}
|
||||
|
||||
public TabStripItem? TabStripItem { get; set; }
|
||||
|
||||
public event EventHandler<RoutedEventArgs>? CloseTab
|
||||
{
|
||||
add => AddHandler(CloseTabEvent, value);
|
||||
remove => RemoveHandler(CloseTabEvent, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private IconButton? _iconButton;
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
_iconButton = e.NameScope.Find<IconButton>(TabStripMenuItemTheme.ItemCloseButtonPart);
|
||||
if (_iconButton is not null) {
|
||||
_iconButton.Click += (sender, args) =>
|
||||
{
|
||||
var menu = this.FindLogicalAncestorOfType<MenuBase>();
|
||||
if (menu is not null) {
|
||||
menu.Close();
|
||||
var eventArgs = new RoutedEventArgs(CloseTabEvent);
|
||||
RaiseEvent(eventArgs);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,141 @@
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Media;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Theme.Utils;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class TabStripMenuItemTheme : BaseControlTheme
|
||||
{
|
||||
public const string ItemDecoratorPart = "Part_ItemDecorator";
|
||||
public const string MainContainerPart = "Part_MainContainer";
|
||||
public const string ItemTextPresenterPart = "Part_ItemTextPresenter";
|
||||
public const string ItemCloseButtonPart = "Part_ItemCloseIcon";
|
||||
|
||||
public TabStripMenuItemTheme()
|
||||
: base(typeof(TabStripMenuItem))
|
||||
{
|
||||
}
|
||||
|
||||
protected override IControlTemplate BuildControlTemplate()
|
||||
{
|
||||
return new FuncControlTemplate<TabStripMenuItem>((item, scope) =>
|
||||
{
|
||||
var container = new Border()
|
||||
{
|
||||
Name = ItemDecoratorPart
|
||||
};
|
||||
var transitions = new Transitions();
|
||||
transitions.Add(AnimationUtils.CreateTransition<SolidColorBrushTransition>(Border.BackgroundProperty));
|
||||
container.Transitions = transitions;
|
||||
|
||||
var layout = new Grid()
|
||||
{
|
||||
Name = MainContainerPart,
|
||||
ColumnDefinitions =
|
||||
{
|
||||
new ColumnDefinition(GridLength.Star),
|
||||
new ColumnDefinition(GridLength.Auto)
|
||||
{
|
||||
SharedSizeGroup = "MenuCloseIcon"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var itemTextPresenter = new ContentPresenter
|
||||
{
|
||||
Name = ItemTextPresenterPart,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
RecognizesAccessKey = true,
|
||||
IsHitTestVisible = false
|
||||
};
|
||||
|
||||
Grid.SetColumn(itemTextPresenter, 0);
|
||||
TokenResourceBinder.CreateTokenBinding(itemTextPresenter, ContentPresenter.MarginProperty, MenuResourceKey.ItemMargin);
|
||||
CreateTemplateParentBinding(itemTextPresenter, ContentPresenter.ContentProperty, TabStripMenuItem.HeaderProperty);
|
||||
CreateTemplateParentBinding(itemTextPresenter, ContentPresenter.ContentTemplateProperty, TabStripMenuItem.HeaderTemplateProperty);
|
||||
|
||||
itemTextPresenter.RegisterInNameScope(scope);
|
||||
|
||||
var menuCloseIcon = new PathIcon
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Right,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Kind = "CloseOutlined"
|
||||
};
|
||||
|
||||
var closeButton = new IconButton()
|
||||
{
|
||||
Name = ItemCloseButtonPart,
|
||||
HorizontalAlignment = HorizontalAlignment.Right,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Icon = menuCloseIcon
|
||||
};
|
||||
|
||||
|
||||
CreateTemplateParentBinding(closeButton, IconButton.IsVisibleProperty, TabStripMenuItem.IsClosableProperty);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(menuCloseIcon, PathIcon.NormalFilledBrushProperty, GlobalResourceKey.ColorIcon);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(menuCloseIcon, PathIcon.ActiveFilledBrushProperty, GlobalResourceKey.ColorIconHover);
|
||||
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(menuCloseIcon, PathIcon.WidthProperty, GlobalResourceKey.IconSizeSM);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(menuCloseIcon, PathIcon.HeightProperty, GlobalResourceKey.IconSizeSM);
|
||||
|
||||
Grid.SetColumn(menuCloseIcon, 4);
|
||||
closeButton.RegisterInNameScope(scope);
|
||||
|
||||
layout.Children.Add(itemTextPresenter);
|
||||
layout.Children.Add(closeButton);
|
||||
container.Child = layout;
|
||||
|
||||
return container;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
var commonStyle = new Style(selector => selector.Nesting());
|
||||
BuildCommonStyle(commonStyle);
|
||||
BuildDisabledStyle();
|
||||
Add(commonStyle);
|
||||
}
|
||||
|
||||
private void BuildCommonStyle(Style commonStyle)
|
||||
{
|
||||
commonStyle.Add(TabStripMenuItem.ForegroundProperty, MenuResourceKey.ItemColor);
|
||||
{
|
||||
var borderStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart));
|
||||
borderStyle.Add(Border.MinHeightProperty, MenuResourceKey.ItemHeight);
|
||||
borderStyle.Add(Border.PaddingProperty, MenuResourceKey.ItemPaddingInline);
|
||||
borderStyle.Add(Border.BackgroundProperty, MenuResourceKey.ItemBg);
|
||||
borderStyle.Add(Border.CornerRadiusProperty, MenuResourceKey.ItemBorderRadius);
|
||||
commonStyle.Add(borderStyle);
|
||||
}
|
||||
|
||||
// Hover 状态
|
||||
var hoverStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.PointerOver));
|
||||
hoverStyle.Add(TabStripMenuItem.ForegroundProperty, MenuResourceKey.ItemHoverColor);
|
||||
{
|
||||
var borderStyle = new Style(selector => selector.Nesting().Template().Name(ItemDecoratorPart));
|
||||
borderStyle.Add(Border.BackgroundProperty, MenuResourceKey.ItemHoverBg);
|
||||
hoverStyle.Add(borderStyle);
|
||||
}
|
||||
commonStyle.Add(hoverStyle);
|
||||
}
|
||||
|
||||
private void BuildDisabledStyle()
|
||||
{
|
||||
var disabledStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Disabled));
|
||||
disabledStyle.Add(TabStripMenuItem.ForegroundProperty, MenuResourceKey.ItemDisabledColor);
|
||||
Add(disabledStyle);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user