mirror of
https://gitee.com/chinware/atomui.git
synced 2024-12-02 03:47:52 +08:00
完成 CardTabControl 标签布局类
完成 CardTabControl 标签布局类
This commit is contained in:
parent
c92a0f557f
commit
c939b25884
@ -103,6 +103,13 @@
|
||||
<atom:TabStripItem>Tab 2</atom:TabStripItem>
|
||||
<atom:TabStripItem>Tab 3</atom:TabStripItem>
|
||||
</atom:TabStrip>
|
||||
|
||||
<atom:CardTabStrip TabAlignmentCenter="True">
|
||||
<atom:TabStripItem>Tab 1</atom:TabStripItem>
|
||||
<atom:TabStripItem>Tab 2</atom:TabStripItem>
|
||||
<atom:TabStripItem>Tab 3</atom:TabStripItem>
|
||||
</atom:CardTabStrip>
|
||||
|
||||
</StackPanel>
|
||||
</showcase:ShowCaseItem>
|
||||
|
||||
|
@ -27,14 +27,12 @@ internal class CardTabControlTheme : BaseTabControlTheme
|
||||
CreateTemplateParentBinding(alignWrapper, DockPanel.DockProperty, BaseTabControl.TabStripPlacementProperty);
|
||||
CreateTemplateParentBinding(alignWrapper, Panel.MarginProperty,TabControl.TabStripMarginProperty);
|
||||
|
||||
var cardTabStripContainer = new DockPanel()
|
||||
var cardTabControlContainer = new TabsContainerPanel()
|
||||
{
|
||||
Name = TabsContainerPart,
|
||||
};
|
||||
cardTabStripContainer.RegisterInNameScope(scope);
|
||||
|
||||
TokenResourceBinder.CreateTokenBinding(cardTabStripContainer, StackPanel.SpacingProperty,
|
||||
TabControlResourceKey.CardGutter);
|
||||
cardTabControlContainer.RegisterInNameScope(scope);
|
||||
CreateTemplateParentBinding(cardTabControlContainer, TabsContainerPanel.TabStripPlacementProperty, TabStrip.TabStripPlacementProperty);
|
||||
|
||||
var tabScrollViewer = new TabControlScrollViewer()
|
||||
{
|
||||
@ -64,6 +62,7 @@ internal class CardTabControlTheme : BaseTabControlTheme
|
||||
BorderThickness = new Thickness(1),
|
||||
Icon = addTabIcon
|
||||
};
|
||||
DockPanel.SetDock(addTabButton, Dock.Right);
|
||||
|
||||
CreateTemplateParentBinding(addTabButton, IconButton.BorderThicknessProperty, CardTabControl.CardBorderThicknessProperty);
|
||||
CreateTemplateParentBinding(addTabButton, IconButton.CornerRadiusProperty, CardTabControl.CardBorderRadiusProperty);
|
||||
@ -73,10 +72,10 @@ internal class CardTabControlTheme : BaseTabControlTheme
|
||||
|
||||
addTabButton.RegisterInNameScope(scope);
|
||||
|
||||
cardTabStripContainer.Children.Add(addTabButton);
|
||||
cardTabStripContainer.Children.Add(tabScrollViewer);
|
||||
cardTabControlContainer.TabScrollViewer = tabScrollViewer;
|
||||
cardTabControlContainer.AddTabButton = addTabButton;
|
||||
|
||||
alignWrapper.Children.Add(cardTabStripContainer);
|
||||
alignWrapper.Children.Add(cardTabControlContainer);
|
||||
|
||||
container.Children.Add(alignWrapper);
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ internal class TabScrollContentPresenter : ScrollContentPresenter, ICustomHitTes
|
||||
var x = Offset.X;
|
||||
var y = Offset.Y;
|
||||
var delta = e.Delta;
|
||||
|
||||
if (TabStripPlacement == Dock.Top || TabStripPlacement == Dock.Bottom) {
|
||||
delta = new Vector(delta.Y, delta.X);
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ internal class BaseTabStripTheme : BaseControlTheme
|
||||
{
|
||||
public const string FrameDecoratorPart = "PART_FrameDecorator";
|
||||
public const string ItemsPresenterPart = "PART_ItemsPresenter";
|
||||
public const string TabsContainerPart = "PART_TabsContainer";
|
||||
public const string AlignWrapperPart = "PART_AlignWrapper";
|
||||
|
||||
public BaseTabStripTheme(Type targetType) : base(targetType) { }
|
||||
|
||||
@ -50,9 +52,9 @@ internal class BaseTabStripTheme : BaseControlTheme
|
||||
// tabs 是否居中
|
||||
var tabAlignCenterStyle = new Style(selector => selector.Nesting().PropertyEquals(TabStrip.TabAlignmentCenterProperty, true));
|
||||
{
|
||||
var itemsPresenterStyle = new Style(selector => selector.Nesting().Template().Name(ItemsPresenterPart));
|
||||
itemsPresenterStyle.Add(ItemsPresenter.HorizontalAlignmentProperty, HorizontalAlignment.Center);
|
||||
tabAlignCenterStyle.Add(itemsPresenterStyle);
|
||||
var tabsContainerStyle = new Style(selector => selector.Nesting().Template().Name(TabsContainerPart));
|
||||
tabsContainerStyle.Add(ItemsPresenter.HorizontalAlignmentProperty, HorizontalAlignment.Center);
|
||||
tabAlignCenterStyle.Add(tabsContainerStyle);
|
||||
}
|
||||
topStyle.Add(tabAlignCenterStyle);
|
||||
|
||||
@ -69,9 +71,9 @@ internal class BaseTabStripTheme : BaseControlTheme
|
||||
// tabs 是否居中
|
||||
var tabAlignCenterStyle = new Style(selector => selector.Nesting().PropertyEquals(TabStrip.TabAlignmentCenterProperty, true));
|
||||
{
|
||||
var itemsPresenterStyle = new Style(selector => selector.Nesting().Template().Name(ItemsPresenterPart));
|
||||
itemsPresenterStyle.Add(ItemsPresenter.VerticalAlignmentProperty, VerticalAlignment.Center);
|
||||
tabAlignCenterStyle.Add(itemsPresenterStyle);
|
||||
var tabsContainerStyle = new Style(selector => selector.Nesting().Template().Name(TabsContainerPart));
|
||||
tabsContainerStyle.Add(ItemsPresenter.VerticalAlignmentProperty, VerticalAlignment.Center);
|
||||
tabAlignCenterStyle.Add(tabsContainerStyle);
|
||||
}
|
||||
rightStyle.Add(tabAlignCenterStyle);
|
||||
|
||||
@ -86,9 +88,9 @@ internal class BaseTabStripTheme : BaseControlTheme
|
||||
// tabs 是否居中
|
||||
var tabAlignCenterStyle = new Style(selector => selector.Nesting().PropertyEquals(TabStrip.TabAlignmentCenterProperty, true));
|
||||
{
|
||||
var itemsPresenterStyle = new Style(selector => selector.Nesting().Template().Name(ItemsPresenterPart));
|
||||
itemsPresenterStyle.Add(ItemsPresenter.HorizontalAlignmentProperty, HorizontalAlignment.Center);
|
||||
tabAlignCenterStyle.Add(itemsPresenterStyle);
|
||||
var tabsContainerStyle = new Style(selector => selector.Nesting().Template().Name(TabsContainerPart));
|
||||
tabsContainerStyle.Add(ItemsPresenter.HorizontalAlignmentProperty, HorizontalAlignment.Center);
|
||||
tabAlignCenterStyle.Add(tabsContainerStyle);
|
||||
}
|
||||
bottomStyle.Add(tabAlignCenterStyle);
|
||||
|
||||
@ -105,9 +107,9 @@ internal class BaseTabStripTheme : BaseControlTheme
|
||||
// tabs 是否居中
|
||||
var tabAlignCenterStyle = new Style(selector => selector.Nesting().PropertyEquals(TabStrip.TabAlignmentCenterProperty, true));
|
||||
{
|
||||
var itemsPresenterStyle = new Style(selector => selector.Nesting().Template().Name(ItemsPresenterPart));
|
||||
itemsPresenterStyle.Add(ItemsPresenter.VerticalAlignmentProperty, VerticalAlignment.Center);
|
||||
tabAlignCenterStyle.Add(itemsPresenterStyle);
|
||||
var tabsContainerStyle = new Style(selector => selector.Nesting().Template().Name(TabsContainerPart));
|
||||
tabsContainerStyle.Add(ItemsPresenter.VerticalAlignmentProperty, VerticalAlignment.Center);
|
||||
tabAlignCenterStyle.Add(tabsContainerStyle);
|
||||
}
|
||||
leftStyle.Add(tabAlignCenterStyle);
|
||||
|
||||
|
@ -127,37 +127,10 @@ public class CardTabStrip : BaseTabStrip, IControlCustomStyle
|
||||
if (change.Property == SizeTypeProperty) {
|
||||
HandleSizeTypeChanged();
|
||||
} else if (change.Property == TabStripPlacementProperty) {
|
||||
SetupCardTabStripContainer();
|
||||
HandleTabStripPlacementChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupCardTabStripContainer(Size finalSize)
|
||||
{
|
||||
if (_cardTabStripContainer is not null) {
|
||||
double addButtonOffset = 0;
|
||||
double markOffset = 0;
|
||||
if (TabStripPlacement == Dock.Top || TabStripPlacement == Dock.Bottom) {
|
||||
addButtonOffset = _addTabButton?.Bounds.Right ?? 0;
|
||||
markOffset = finalSize.Width;
|
||||
if (addButtonOffset > markOffset) {
|
||||
_cardTabStripContainer.ColumnDefinitions[0].Width = GridLength.Star;
|
||||
} else {
|
||||
_cardTabStripContainer.ColumnDefinitions[0].Width = GridLength.Auto;
|
||||
}
|
||||
} else {
|
||||
addButtonOffset = _addTabButton?.Bounds.Bottom ?? 0;
|
||||
markOffset = finalSize.Height;
|
||||
if (addButtonOffset > markOffset) {
|
||||
_cardTabStripContainer.RowDefinitions[0].Height = GridLength.Star;
|
||||
} else {
|
||||
_cardTabStripContainer.RowDefinitions[0].Height = GridLength.Auto;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#region IControlCustomStyle 实现
|
||||
|
||||
void IControlCustomStyle.HandleTemplateApplied(INameScope scope)
|
||||
@ -170,7 +143,6 @@ public class CardTabStrip : BaseTabStrip, IControlCustomStyle
|
||||
_addTabButton.Click += HandleAddButtonClicked;
|
||||
}
|
||||
HandleSizeTypeChanged();
|
||||
SetupCardTabStripContainer();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -193,57 +165,10 @@ public class CardTabStrip : BaseTabStrip, IControlCustomStyle
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
var size = base.ArrangeOverride(finalSize);
|
||||
SetupCardTabStripContainer(finalSize);
|
||||
HandleTabStripPlacementChanged();
|
||||
return size;
|
||||
}
|
||||
|
||||
private void SetupCardTabStripContainer()
|
||||
{
|
||||
if (TabStripPlacement == Dock.Top ||
|
||||
TabStripPlacement == Dock.Bottom) {
|
||||
if (_cardTabStripContainer is not null) {
|
||||
_cardTabStripContainer.Children.Clear();
|
||||
_cardTabStripContainer.RowDefinitions.Clear();
|
||||
_cardTabStripContainer.ColumnDefinitions = new ColumnDefinitions()
|
||||
{
|
||||
new ColumnDefinition(GridLength.Auto),
|
||||
new ColumnDefinition(GridLength.Auto),
|
||||
};
|
||||
}
|
||||
|
||||
if (_tabScrollViewer is not null) {
|
||||
Grid.SetColumn(_tabScrollViewer, 0);
|
||||
}
|
||||
|
||||
if (_addTabButton is not null) {
|
||||
Grid.SetColumn(_addTabButton, 1);
|
||||
}
|
||||
|
||||
_cardTabStripContainer!.Children.Add(_tabScrollViewer!);
|
||||
_cardTabStripContainer.Children.Add(_addTabButton!);
|
||||
} else {
|
||||
if (_cardTabStripContainer is not null) {
|
||||
_cardTabStripContainer.Children.Clear();
|
||||
_cardTabStripContainer.ColumnDefinitions.Clear();
|
||||
_cardTabStripContainer.RowDefinitions = new RowDefinitions()
|
||||
{
|
||||
new RowDefinition(GridLength.Auto),
|
||||
new RowDefinition(GridLength.Auto),
|
||||
};
|
||||
}
|
||||
if (_tabScrollViewer is not null) {
|
||||
Grid.SetRow(_tabScrollViewer, 0);
|
||||
}
|
||||
|
||||
if (_addTabButton is not null) {
|
||||
Grid.SetRow(_addTabButton, 1);
|
||||
}
|
||||
_cardTabStripContainer!.Children.Add(_tabScrollViewer!);
|
||||
_cardTabStripContainer.Children.Add(_addTabButton!);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleTabStripPlacementChanged()
|
||||
{
|
||||
if (TabStripPlacement == Dock.Top) {
|
||||
|
@ -20,14 +20,16 @@ internal class CardTabStripTheme : BaseTabStripTheme
|
||||
|
||||
protected override void NotifyBuildControlTemplate(BaseTabStrip baseTabStrip, INameScope scope, Border container)
|
||||
{
|
||||
var cardTabStripContainer = new Grid()
|
||||
var alignWrapper = new Panel()
|
||||
{
|
||||
Name = CardTabStripContainerPart,
|
||||
Name = AlignWrapperPart
|
||||
};
|
||||
var cardTabStripContainer = new TabsContainerPanel()
|
||||
{
|
||||
Name = TabsContainerPart,
|
||||
};
|
||||
cardTabStripContainer.RegisterInNameScope(scope);
|
||||
|
||||
TokenResourceBinder.CreateTokenBinding(cardTabStripContainer, StackPanel.SpacingProperty,
|
||||
TabControlResourceKey.CardGutter);
|
||||
CreateTemplateParentBinding(cardTabStripContainer, TabsContainerPanel.TabStripPlacementProperty, TabStrip.TabStripPlacementProperty);
|
||||
|
||||
var tabScrollViewer = new TabStripScrollViewer()
|
||||
{
|
||||
@ -66,9 +68,12 @@ internal class CardTabStripTheme : BaseTabStripTheme
|
||||
|
||||
addTabButton.RegisterInNameScope(scope);
|
||||
|
||||
cardTabStripContainer.Children.Add(tabScrollViewer);
|
||||
cardTabStripContainer.Children.Add(addTabButton);
|
||||
container.Child = cardTabStripContainer;
|
||||
cardTabStripContainer.TabScrollViewer = tabScrollViewer;
|
||||
cardTabStripContainer.AddTabButton = addTabButton;
|
||||
|
||||
alignWrapper.Children.Add(cardTabStripContainer);
|
||||
|
||||
container.Child = alignWrapper;
|
||||
}
|
||||
|
||||
private ItemsPresenter CreateTabStripContentPanel(INameScope scope)
|
||||
|
@ -17,12 +17,23 @@ internal class TabStripTheme : BaseTabStripTheme
|
||||
|
||||
protected override void NotifyBuildControlTemplate(BaseTabStrip baseTabStrip, INameScope scope, Border container)
|
||||
{
|
||||
var tabScrollViewer = new TabStripScrollViewer();
|
||||
var alignWrapper = new Panel()
|
||||
{
|
||||
Name = AlignWrapperPart
|
||||
};
|
||||
alignWrapper.RegisterInNameScope(scope);
|
||||
|
||||
var tabScrollViewer = new TabStripScrollViewer()
|
||||
{
|
||||
Name = TabsContainerPart
|
||||
};
|
||||
CreateTemplateParentBinding(tabScrollViewer, BaseTabScrollViewer.TabStripPlacementProperty, TabStrip.TabStripPlacementProperty);
|
||||
var contentPanel = CreateTabStripContentPanel(scope);
|
||||
tabScrollViewer.Content = contentPanel;
|
||||
tabScrollViewer.TabStrip = baseTabStrip;
|
||||
container.Child = tabScrollViewer;
|
||||
|
||||
alignWrapper.Children.Add(tabScrollViewer);
|
||||
container.Child = alignWrapper;
|
||||
}
|
||||
|
||||
private Panel CreateTabStripContentPanel(INameScope scope)
|
||||
|
115
src/AtomUI.Controls/TabControl/TabsContainerPanel.cs
Normal file
115
src/AtomUI.Controls/TabControl/TabsContainerPanel.cs
Normal file
@ -0,0 +1,115 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
internal class TabsContainerPanel : Panel
|
||||
{
|
||||
#region 公共属性定义
|
||||
|
||||
public static readonly DirectProperty<TabsContainerPanel, BaseTabScrollViewer?> TabScrollViewerProperty =
|
||||
AvaloniaProperty.RegisterDirect<TabsContainerPanel, BaseTabScrollViewer?>(nameof(TabScrollViewer),
|
||||
o => o.TabScrollViewer,
|
||||
(o, v) => o.TabScrollViewer = v);
|
||||
|
||||
private BaseTabScrollViewer? _tabScrollViewer;
|
||||
public BaseTabScrollViewer? TabScrollViewer
|
||||
{
|
||||
get => _tabScrollViewer;
|
||||
set => SetAndRaise(TabScrollViewerProperty, ref _tabScrollViewer, value);
|
||||
}
|
||||
|
||||
public static readonly DirectProperty<TabsContainerPanel, IconButton?> AddTabButtonProperty =
|
||||
AvaloniaProperty.RegisterDirect<TabsContainerPanel, IconButton?>(nameof(AddTabButton),
|
||||
o => o.AddTabButton,
|
||||
(o, v) => o.AddTabButton = v);
|
||||
|
||||
private IconButton? _addTabButton;
|
||||
public IconButton? AddTabButton
|
||||
{
|
||||
get => _addTabButton;
|
||||
set => SetAndRaise(AddTabButtonProperty, ref _addTabButton, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 内部属性定义
|
||||
|
||||
internal static readonly DirectProperty<TabsContainerPanel, Dock> TabStripPlacementProperty =
|
||||
AvaloniaProperty.RegisterDirect<TabsContainerPanel, Dock>(nameof(TabStripPlacement),
|
||||
o => o.TabStripPlacement,
|
||||
(o, v) => o.TabStripPlacement = v);
|
||||
|
||||
private Dock _tabStripPlacement;
|
||||
|
||||
internal Dock TabStripPlacement
|
||||
{
|
||||
get => _tabStripPlacement;
|
||||
set => SetAndRaise(TabStripPlacementProperty, ref _tabStripPlacement, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
static TabsContainerPanel()
|
||||
{
|
||||
AffectsMeasure<TabsContainerPanel>(TabScrollViewerProperty, AddTabButtonProperty);
|
||||
AffectsArrange<TabsContainerPanel>(TabStripPlacementProperty);
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size arrangeSize)
|
||||
{
|
||||
// TODO 暂时不做验证,默认认为两个元素都存在
|
||||
// 理论上这里要报错,但是我们是内部使用
|
||||
if (_tabScrollViewer is not null && _addTabButton is not null) {
|
||||
if (TabStripPlacement == Dock.Top || TabStripPlacement == Dock.Bottom) {
|
||||
var scrollViewerDesiredWidth = _tabScrollViewer.DesiredSize.Width;
|
||||
var addTabButtonDesiredWidth = _addTabButton.DesiredSize.Width;
|
||||
var totalDesiredWidth = scrollViewerDesiredWidth + addTabButtonDesiredWidth;
|
||||
if (totalDesiredWidth > arrangeSize.Width) {
|
||||
_tabScrollViewer.Arrange(new Rect(new Point(0, 0), new Size(arrangeSize.Width - addTabButtonDesiredWidth, arrangeSize.Height)));
|
||||
_addTabButton.Arrange(new Rect(new Point(arrangeSize.Width - addTabButtonDesiredWidth, 0), _addTabButton.DesiredSize));
|
||||
} else {
|
||||
_tabScrollViewer.Arrange(new Rect(new Point(0, 0), _tabScrollViewer.DesiredSize));
|
||||
_addTabButton.Arrange(new Rect(new Point(scrollViewerDesiredWidth, 0), _addTabButton.DesiredSize));
|
||||
}
|
||||
} else {
|
||||
var scrollViewerDesiredHeight = _tabScrollViewer.DesiredSize.Height;
|
||||
var addTabButtonDesiredHeight = _addTabButton.DesiredSize.Height;
|
||||
var totalDesiredHeight = scrollViewerDesiredHeight + addTabButtonDesiredHeight;
|
||||
if (totalDesiredHeight > arrangeSize.Height) {
|
||||
_tabScrollViewer.Arrange(new Rect(new Point(0, 0), new Size(arrangeSize.Width, arrangeSize.Height - addTabButtonDesiredHeight)));
|
||||
_addTabButton.Arrange(new Rect(new Point(0, arrangeSize.Width - addTabButtonDesiredHeight), _addTabButton.DesiredSize));
|
||||
} else {
|
||||
_tabScrollViewer.Arrange(new Rect(new Point(0, 0), _tabScrollViewer.DesiredSize));
|
||||
_addTabButton.Arrange(new Rect(new Point(scrollViewerDesiredHeight, 0), _addTabButton.DesiredSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (arrangeSize);
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
if (change.Property == TabScrollViewerProperty) {
|
||||
var oldScrollViewer = change.GetOldValue<BaseTabScrollViewer?>();
|
||||
if (oldScrollViewer is not null) {
|
||||
Children.Remove(oldScrollViewer);
|
||||
}
|
||||
|
||||
if (TabScrollViewer is not null) {
|
||||
Children.Add(TabScrollViewer);
|
||||
}
|
||||
} else if (change.Property == AddTabButtonProperty) {
|
||||
var oldAddTabButton = change.GetOldValue<IconButton?>();
|
||||
if (oldAddTabButton is not null) {
|
||||
Children.Remove(oldAddTabButton);
|
||||
}
|
||||
|
||||
if (AddTabButton is not null) {
|
||||
Children.Add(AddTabButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user