mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-22 09:23:53 +08:00
实现 BaseTabControl
完成基础的 BaseTabControl 类,支持两个风格
This commit is contained in:
@@ -1,6 +1,126 @@
|
||||
namespace AtomUI.Controls;
|
||||
using AtomUI.Data;
|
||||
using AtomUI.Theme.Data;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.LogicalTree;
|
||||
using Avalonia.Media;
|
||||
|
||||
public class BaseTabControl
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
using AvaloniaTabControl = Avalonia.Controls.TabControl;
|
||||
|
||||
public class BaseTabControl : AvaloniaTabControl
|
||||
{
|
||||
public const string TopPC = ":top";
|
||||
public const string RightPC = ":right";
|
||||
public const string BottomPC = ":bottom";
|
||||
public const string LeftPC = ":left";
|
||||
|
||||
private static readonly FuncTemplate<Panel?> DefaultPanel =
|
||||
new(() => new StackPanel());
|
||||
|
||||
#region 公共属性定义
|
||||
public static readonly StyledProperty<SizeType> SizeTypeProperty =
|
||||
AvaloniaProperty.Register<BaseTabControl, SizeType>(nameof(SizeType), SizeType.Middle);
|
||||
|
||||
public static readonly StyledProperty<bool> TabAlignmentCenterProperty =
|
||||
AvaloniaProperty.Register<BaseTabControl, bool>(nameof(TabAlignmentCenter), false);
|
||||
|
||||
public SizeType SizeType
|
||||
{
|
||||
get => GetValue(SizeTypeProperty);
|
||||
set => SetValue(SizeTypeProperty, value);
|
||||
}
|
||||
|
||||
public bool TabAlignmentCenter
|
||||
{
|
||||
get => GetValue(TabAlignmentCenterProperty);
|
||||
set => SetValue(TabAlignmentCenterProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Border? _frameDecorator;
|
||||
|
||||
static BaseTabControl()
|
||||
{
|
||||
ItemsPanelProperty.OverrideDefaultValue<BaseTabControl>(DefaultPanel);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
_frameDecorator = e.NameScope.Find<Border>(BaseTabControlTheme.FrameDecoratorPart);
|
||||
SetupBorderBinding();
|
||||
}
|
||||
|
||||
private void SetupBorderBinding()
|
||||
{
|
||||
if (_frameDecorator is not null) {
|
||||
TokenResourceBinder.CreateTokenBinding(this, BorderThicknessProperty, GlobalResourceKey.BorderThickness, BindingPriority.Template,
|
||||
new RenderScaleAwareThicknessConfigure(this));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PrepareContainerForItemOverride(Control container, object? item, int index)
|
||||
{
|
||||
base.PrepareContainerForItemOverride(container, item, index);
|
||||
if (container is TabItem tabItem) {
|
||||
BindUtils.RelayBind(this, SizeTypeProperty, tabItem, TabItem.SizeTypeProperty);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToLogicalTree(e);
|
||||
UpdatePseudoClasses();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
if (change.Property == TabStripPlacementProperty) {
|
||||
UpdatePseudoClasses();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePseudoClasses()
|
||||
{
|
||||
PseudoClasses.Set(TopPC, TabStripPlacement == Dock.Top);
|
||||
PseudoClasses.Set(RightPC, TabStripPlacement == Dock.Right);
|
||||
PseudoClasses.Set(BottomPC, TabStripPlacement == Dock.Bottom);
|
||||
PseudoClasses.Set(LeftPC, TabStripPlacement == Dock.Left);
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
Point startPoint = default;
|
||||
Point endPoint = default;
|
||||
var borderThickness = BorderThickness.Left;
|
||||
var offsetDelta = borderThickness / 2;
|
||||
if (TabStripPlacement == Dock.Top) {
|
||||
startPoint = new Point(0, Bounds.Height - offsetDelta);
|
||||
endPoint = new Point(Bounds.Width, Bounds.Height - offsetDelta);
|
||||
} else if (TabStripPlacement == Dock.Right) {
|
||||
startPoint = new Point(offsetDelta, 0);
|
||||
endPoint = new Point(offsetDelta, Bounds.Height);
|
||||
} else if (TabStripPlacement == Dock.Bottom) {
|
||||
startPoint = new Point(0, offsetDelta);
|
||||
endPoint = new Point(Bounds.Width, offsetDelta);
|
||||
} else {
|
||||
startPoint = new Point(Bounds.Width - offsetDelta, 0);
|
||||
endPoint = new Point(Bounds.Width - offsetDelta, Bounds.Height);
|
||||
}
|
||||
|
||||
using var optionState = context.PushRenderOptions(new RenderOptions()
|
||||
{
|
||||
EdgeMode = EdgeMode.Aliased
|
||||
});
|
||||
context.DrawLine(new Pen(BorderBrush, borderThickness), startPoint, endPoint);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
internal class BaseTabControlTheme : BaseControlTheme
|
||||
{
|
||||
public const string FrameDecoratorPart = "PART_FrameDecorator";
|
||||
public const string ItemsPresenterPart = "PART_ItemsPresenter";
|
||||
public const string MainLayoutContainerPart = "PART_MainLayoutContainer";
|
||||
public const string SelectedContentHostPart = "PART_SelectedContentHost";
|
||||
|
||||
public BaseTabControlTheme(Type targetType) : base(targetType) { }
|
||||
|
||||
protected override IControlTemplate BuildControlTemplate()
|
||||
{
|
||||
return new FuncControlTemplate<BaseTabControl>((baseTabControl, scope) =>
|
||||
{
|
||||
var frameDecorator = new Border()
|
||||
{
|
||||
Name = FrameDecoratorPart
|
||||
};
|
||||
frameDecorator.RegisterInNameScope(scope);
|
||||
var layoutContainer = new DockPanel()
|
||||
{
|
||||
Name = MainLayoutContainerPart
|
||||
};
|
||||
|
||||
NotifyBuildTabStripTemplate(baseTabControl, scope, layoutContainer);
|
||||
NotifyBuildContentPresenter(baseTabControl, scope, layoutContainer);
|
||||
|
||||
return frameDecorator;
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void NotifyBuildTabStripTemplate(BaseTabControl baseTabControl, INameScope scope, DockPanel container)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void NotifyBuildContentPresenter(BaseTabControl baseTabControl, INameScope scope, DockPanel container)
|
||||
{
|
||||
var contentPresenter = new ContentPresenter
|
||||
{
|
||||
Name = SelectedContentHostPart
|
||||
};
|
||||
contentPresenter.RegisterInNameScope(scope);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.MarginProperty, BaseTabControl.PaddingProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentProperty, BaseTabControl.SelectedContentProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentTemplateProperty, BaseTabControl.SelectedContentTemplateProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.HorizontalContentAlignmentProperty, BaseTabControl.HorizontalContentAlignmentProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.VerticalContentAlignmentProperty, BaseTabControl.VerticalContentAlignmentProperty);
|
||||
container.Children.Add(contentPresenter);
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
base.BuildStyles();
|
||||
var commonStyle = new Style(selector => selector.Nesting());
|
||||
commonStyle.Add(BaseTabControl.BorderBrushProperty, GlobalResourceKey.ColorBorderSecondary);
|
||||
|
||||
// 设置 items presenter 是否居中
|
||||
// 分为上、右、下、左
|
||||
{
|
||||
// 上
|
||||
var topStyle = new Style(selector => selector.Nesting().Class(BaseTabControl.TopPC));
|
||||
topStyle.Add(BaseTabControl.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
|
||||
topStyle.Add(BaseTabControl.VerticalAlignmentProperty, VerticalAlignment.Top);
|
||||
|
||||
// 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);
|
||||
}
|
||||
topStyle.Add(tabAlignCenterStyle);
|
||||
|
||||
commonStyle.Add(topStyle);
|
||||
}
|
||||
|
||||
{
|
||||
// 右
|
||||
var rightStyle = new Style(selector => selector.Nesting().Class(BaseTabControl.RightPC));
|
||||
|
||||
rightStyle.Add(BaseTabControl.HorizontalAlignmentProperty, HorizontalAlignment.Left);
|
||||
rightStyle.Add(BaseTabControl.VerticalAlignmentProperty, VerticalAlignment.Stretch);
|
||||
|
||||
// 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);
|
||||
}
|
||||
rightStyle.Add(tabAlignCenterStyle);
|
||||
|
||||
commonStyle.Add(rightStyle);
|
||||
}
|
||||
{
|
||||
// 下
|
||||
var bottomStyle = new Style(selector => selector.Nesting().Class(BaseTabControl.BottomPC));
|
||||
bottomStyle.Add(BaseTabControl.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
|
||||
bottomStyle.Add(BaseTabControl.VerticalAlignmentProperty, VerticalAlignment.Top);
|
||||
|
||||
// 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);
|
||||
}
|
||||
bottomStyle.Add(tabAlignCenterStyle);
|
||||
|
||||
commonStyle.Add(bottomStyle);
|
||||
}
|
||||
{
|
||||
// 左
|
||||
var leftStyle = new Style(selector => selector.Nesting().Class(BaseTabControl.LeftPC));
|
||||
|
||||
|
||||
leftStyle.Add(BaseTabControl.HorizontalAlignmentProperty, HorizontalAlignment.Left);
|
||||
leftStyle.Add(BaseTabControl.VerticalAlignmentProperty, VerticalAlignment.Stretch);
|
||||
|
||||
// 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);
|
||||
}
|
||||
leftStyle.Add(tabAlignCenterStyle);
|
||||
|
||||
commonStyle.Add(leftStyle);
|
||||
}
|
||||
|
||||
Add(commonStyle);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user