From 02a74a855e384d593be4fde15536299cd91c2f8d Mon Sep 17 00:00:00 2001 From: polarboy Date: Wed, 17 Jul 2024 17:49:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=20tooltip=20=E6=94=B9?= =?UTF-8?q?=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AtomUI.Base/Utils/BindUtils.cs | 2 +- .../Loading/LoadingIndicator.cs | 3 +- src/AtomUI.Controls/Tooltip/ToolTip.cs | 54 ++++++++----------- .../Tooltip/ToolTipProperties.cs | 35 ++++-------- src/AtomUI.Controls/Tooltip/ToolTipTheme.cs | 53 ++++++++++++++++++ 5 files changed, 88 insertions(+), 59 deletions(-) create mode 100644 src/AtomUI.Controls/Tooltip/ToolTipTheme.cs diff --git a/src/AtomUI.Base/Utils/BindUtils.cs b/src/AtomUI.Base/Utils/BindUtils.cs index 8e5d31259..095b7ef3e 100644 --- a/src/AtomUI.Base/Utils/BindUtils.cs +++ b/src/AtomUI.Base/Utils/BindUtils.cs @@ -50,7 +50,7 @@ public static class BindUtils public static IDisposable CreateTokenBinding(AvaloniaObject target, AvaloniaProperty targetProperty, - string resourceKey) + object resourceKey) { return target.Bind(targetProperty, new DynamicResourceExtension(resourceKey)); } diff --git a/src/AtomUI.Controls/Loading/LoadingIndicator.cs b/src/AtomUI.Controls/Loading/LoadingIndicator.cs index 65fc969ea..84e74d90a 100644 --- a/src/AtomUI.Controls/Loading/LoadingIndicator.cs +++ b/src/AtomUI.Controls/Loading/LoadingIndicator.cs @@ -1,5 +1,4 @@ -using AtomUI.Data; -using AtomUI.Icon; +using AtomUI.Icon; using AtomUI.Styling; using AtomUI.Utils; using Avalonia; diff --git a/src/AtomUI.Controls/Tooltip/ToolTip.cs b/src/AtomUI.Controls/Tooltip/ToolTip.cs index 13759766c..617d965ba 100644 --- a/src/AtomUI.Controls/Tooltip/ToolTip.cs +++ b/src/AtomUI.Controls/Tooltip/ToolTip.cs @@ -24,7 +24,7 @@ namespace AtomUI.Controls; using AvaloniaWin = Avalonia.Controls.Window; [PseudoClasses(StdPseudoClass.Open)] -public partial class ToolTip : StyledControl, +public partial class ToolTip : TemplatedControl, IShadowMaskInfoProvider, IControlCustomStyle { @@ -49,9 +49,8 @@ public partial class ToolTip : StyledControl, typeof(ThemeVariant).GetFieldInfoOrThrow("RequestedThemeVariantProperty", BindingFlags.Static | BindingFlags.NonPublic); RequestedThemeVariantProperty = (StyledProperty)requestedThemeVariantProperty.GetValue(null)!; - AffectsRender(DefaultBgTokenProperty, - ForegroundProperty, - BackgroundProperty); + AffectsRender(ForegroundProperty, + BackgroundProperty); AffectsArrange(FlipPlacementProperty); } @@ -468,7 +467,7 @@ public partial class ToolTip : StyledControl, var marginToAnchor = GetMarginToAnchor(control); if (double.IsNaN(marginToAnchor)) { - marginToAnchor = _marginXXS / 2; + marginToAnchor = _marginXXSToken / 2; } var placement = GetPlacement(control); @@ -542,7 +541,7 @@ public partial class ToolTip : StyledControl, var topLevel = TopLevel.GetTopLevel(placementTarget); var motionActor = - new PopupMotionActor(_shadows, positionInfo.Offset, positionInfo.Scaling, contentControl, motion); + new PopupMotionActor(_shadowsToken, positionInfo.Offset, positionInfo.Scaling, contentControl, motion); motionActor.DispatchInSceneLayer = true; motionActor.SceneParent = topLevel; motionActor.Completed += (sender, args) => @@ -607,7 +606,7 @@ public partial class ToolTip : StyledControl, UIStructureUtils.SetVisualParent(popup.Child, null); UIStructureUtils.SetVisualParent(popup.Child, null); - var motionActor = new PopupMotionActor(_shadows, _popupPositionInfo.Offset, _popupPositionInfo.Scaling, + var motionActor = new PopupMotionActor(_shadowsToken, _popupPositionInfo.Offset, _popupPositionInfo.Scaling, popup.Child, motion); motionActor.DispatchInSceneLayer = true; motionActor.SceneParent = placementToplevel; @@ -669,43 +668,34 @@ public partial class ToolTip : StyledControl, } } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + _customStyle.HandleTemplateApplied(e.NameScope); + } + + void IControlCustomStyle.HandleTemplateApplied(INameScope scope) + { + _arrowDecoratedBox = scope.Find(ToolTipTheme.ToolTipContainerPart); + _customStyle.ApplyFixedStyleConfig(); + } + #region IControlCustomStyle 实现 void IControlCustomStyle.SetupUi() { Background = new SolidColorBrush(Colors.Transparent); - _arrowDecoratedBox = new ArrowDecoratedBox(); - if (Content is string text) { - _arrowDecoratedBox.Child = new TextBlock - { - Text = text, - VerticalAlignment = VerticalAlignment.Center, - HorizontalAlignment = HorizontalAlignment.Center, - TextWrapping = TextWrapping.Wrap, - }; - } else if (Content is Control control) { - _arrowDecoratedBox.Child = control; - } - - ((ISetLogicalParent)_arrowDecoratedBox).SetParent(this); - VisualChildren.Add(_arrowDecoratedBox); - _customStyle.ApplyFixedStyleConfig(); + BindUtils.CreateTokenBinding(this, ThemeProperty, typeof(ToolTip)); + // 手动提前应用模板 + ApplyStyling(); + ApplyTemplate(); } void IControlCustomStyle.ApplyFixedStyleConfig() { if (_arrowDecoratedBox is not null) { - _controlTokenBinder.AddControlBinding(_arrowDecoratedBox, FontSizeProperty, GlobalResourceKey.FontSize); - _controlTokenBinder.AddControlBinding(_arrowDecoratedBox, MaxWidthProperty, ToolTipResourceKey.ToolTipMaxWidth); - _controlTokenBinder.AddControlBinding(_arrowDecoratedBox, BackgroundProperty, ToolTipResourceKey.ToolTipBackground); - _controlTokenBinder.AddControlBinding(_arrowDecoratedBox, ForegroundProperty, ToolTipResourceKey.ToolTipColor); - _controlTokenBinder.AddControlBinding(_arrowDecoratedBox, MinHeightProperty, GlobalResourceKey.ControlHeight); - _controlTokenBinder.AddControlBinding(_arrowDecoratedBox, PaddingProperty, ToolTipResourceKey.ToolTipPadding); _controlTokenBinder.AddControlBinding(MarginXXSTokenProperty, GlobalResourceKey.MarginXXS); _controlTokenBinder.AddControlBinding(MotionDurationTokenProperty, GlobalResourceKey.MotionDurationMid); _controlTokenBinder.AddControlBinding(ShadowsTokenProperty, GlobalResourceKey.BoxShadowsSecondary); - _controlTokenBinder.AddControlBinding(_arrowDecoratedBox, ArrowDecoratedBox.CornerRadiusProperty, ToolTipResourceKey.BorderRadiusOuter); - // TODO 生命周期一样还需要管理起来吗? - BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, _arrowDecoratedBox, ArrowDecoratedBox.IsShowArrowProperty); } } diff --git a/src/AtomUI.Controls/Tooltip/ToolTipProperties.cs b/src/AtomUI.Controls/Tooltip/ToolTipProperties.cs index 58d47fd9e..8edfac703 100644 --- a/src/AtomUI.Controls/Tooltip/ToolTipProperties.cs +++ b/src/AtomUI.Controls/Tooltip/ToolTipProperties.cs @@ -114,39 +114,26 @@ public partial class ToolTip // 私有属性 private static StyledProperty RequestedThemeVariantProperty; - private static readonly StyledProperty IsShowArrowEffectiveProperty = + internal static readonly StyledProperty IsShowArrowEffectiveProperty = ArrowDecoratedBox.IsShowArrowProperty.AddOwner(); /// /// 是否实际显示箭头 /// - public bool IsShowArrowEffective + internal bool IsShowArrowEffective { get => GetValue(IsShowArrowEffectiveProperty); set => SetValue(IsShowArrowEffectiveProperty, value); } // 组件的 Token 绑定属性 - private IBrush? _defaultBackground; - - private static readonly DirectProperty DefaultBgTokenProperty - = AvaloniaProperty.RegisterDirect(nameof(_defaultBackground), - (o) => o._defaultBackground, - (o, v) => o._defaultBackground = v); - - private double _toolTipArrowSize; - - private static readonly DirectProperty ToolTipArrowSizeTokenProperty - = AvaloniaProperty.RegisterDirect(nameof(_toolTipArrowSize), - (o) => o._toolTipArrowSize, - (o, v) => o._toolTipArrowSize = v); - - private double _marginXXS; + + private double _marginXXSToken; private static readonly DirectProperty MarginXXSTokenProperty - = AvaloniaProperty.RegisterDirect(nameof(_marginXXS), - (o) => o._marginXXS, - (o, v) => o._marginXXS = v); + = AvaloniaProperty.RegisterDirect(nameof(_marginXXSToken), + (o) => o._marginXXSToken, + (o, v) => o._marginXXSToken = v); private TimeSpan _motionDuration; @@ -156,12 +143,12 @@ public partial class ToolTip (o, v) => o._motionDuration = v); // 暂时不支持自定义 - private BoxShadows _shadows; + private BoxShadows _shadowsToken; private static readonly DirectProperty ShadowsTokenProperty - = AvaloniaProperty.RegisterDirect(nameof(_shadows), - (o) => o._shadows, - (o, v) => o._shadows = v); + = AvaloniaProperty.RegisterDirect(nameof(_shadowsToken), + (o) => o._shadowsToken, + (o, v) => o._shadowsToken = v); // 组件的 Token 绑定属性 internal static readonly DirectProperty FlipPlacementProperty = diff --git a/src/AtomUI.Controls/Tooltip/ToolTipTheme.cs b/src/AtomUI.Controls/Tooltip/ToolTipTheme.cs new file mode 100644 index 000000000..7a6ea77ce --- /dev/null +++ b/src/AtomUI.Controls/Tooltip/ToolTipTheme.cs @@ -0,0 +1,53 @@ +using AtomUI.Styling; +using AtomUI.Utils; +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using Avalonia.Layout; +using Avalonia.Media; + +namespace AtomUI.Controls; + +[ControlThemeProvider] +public class ToolTipTheme : ControlTheme +{ + public const string ToolTipContainerPart = "PART_ToolTipContainer"; + + public ToolTipTheme() + : base(typeof(ToolTip)) + { + } + + protected override IControlTemplate? BuildControlTemplate() + { + return new FuncControlTemplate((tip, scope) => + { + var arrowDecoratedBox = new ArrowDecoratedBox() + { + Name = ToolTipContainerPart, + }; + if (tip.Content is string text) { + arrowDecoratedBox.Child = new TextBlock + { + Text = text, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Center, + TextWrapping = TextWrapping.Wrap, + }; + } else if (tip.Content is Control control) { + arrowDecoratedBox.Child = control; + } + + BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.FontSizeProperty, GlobalResourceKey.FontSize); + BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.MaxWidthProperty, ToolTipResourceKey.ToolTipMaxWidth); + BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.BackgroundProperty, ToolTipResourceKey.ToolTipBackground); + BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.ForegroundProperty, ToolTipResourceKey.ToolTipColor); + BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.MinHeightProperty, GlobalResourceKey.ControlHeight); + BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.PaddingProperty, ToolTipResourceKey.ToolTipPadding); + BindUtils.CreateTokenBinding(arrowDecoratedBox, ArrowDecoratedBox.CornerRadiusProperty, ToolTipResourceKey.BorderRadiusOuter); + + CreateTemplateParentBinding(arrowDecoratedBox, ArrowDecoratedBox.IsShowArrowProperty, ToolTip.IsShowArrowEffectiveProperty); + arrowDecoratedBox.RegisterInNameScope(scope); + return arrowDecoratedBox; + }); + } +} \ No newline at end of file