Add ITokenResourceConsumer

This commit is contained in:
chinboy
2025-02-28 22:58:45 +08:00
parent a8d0715018
commit aecae7ff6c
6 changed files with 102 additions and 66 deletions
@@ -1,5 +1,4 @@
using AtomUI.Data;
using Avalonia;
using Avalonia.Controls;
namespace AtomUI.Controls;
+6 -14
View File
@@ -1,6 +1,5 @@
using System.ComponentModel;
using System.Reactive.Disposables;
using System.Runtime.CompilerServices;
using AtomUI.Data;
using AtomUI.Theme.Data;
using AtomUI.Theme.Styling;
@@ -126,14 +125,6 @@ public class Flyout : PopupFlyoutBase
IsShowArrowProperty.OverrideDefaultValue<Flyout>(false);
}
public Flyout()
{
TokenResourceBinder.CreateGlobalTokenBinding(this, MotionDurationTokenProperty,
SharedTokenKey.MotionDurationMid);
TokenResourceBinder.CreateGlobalTokenBinding(this, MaskShadowsProperty,
SharedTokenKey.BoxShadowsSecondary);
}
private void HandlePopupPropertyChanged(AvaloniaPropertyChangedEventArgs args)
{
SetupArrowPosition(Popup);
@@ -210,11 +201,15 @@ public class Flyout : PopupFlyoutBase
{
CompositeDisposable.Add(PopupControl.IsFlippedProperty.Changed.Subscribe(HandlePopupPropertyChanged));
}
CompositeDisposable.Add(TokenResourceBinder.CreateGlobalTokenBinding(this, MotionDurationTokenProperty,
SharedTokenKey.MotionDurationMid));
CompositeDisposable.Add(TokenResourceBinder.CreateGlobalTokenBinding(this, MaskShadowsProperty,
SharedTokenKey.BoxShadowsSecondary));
}
protected override void OnClosed()
{
base.OnClosed();
CompositeDisposable?.Dispose();
}
@@ -348,10 +343,7 @@ public class Flyout : PopupFlyoutBase
IsOpen = true;
Dispatcher.UIThread.InvokeAsync(() =>
{
Popup.MotionAwareOpen(() =>
{
HandlePopupOpened(placementTarget);
});
Popup.MotionAwareOpen(() => { HandlePopupOpened(placementTarget); });
});
return true;
}
@@ -122,9 +122,8 @@ internal class InfoPickerInputTheme : BaseControlTheme
IsEnableClearButton = false,
IsEnableRevealButton = false,
};
BindUtils.RelayBind(this, DataValidationErrors.ErrorsProperty, pickerTextBox,
DataValidationErrors.ErrorsProperty);
CreateTemplateParentBinding(pickerTextBox, DataValidationErrors.ErrorsProperty, DataValidationErrors.ErrorsProperty);
CreateTemplateParentBinding(pickerTextBox, TextBox.ForegroundProperty, InfoPickerInput.InputTextBrushProperty);
CreateTemplateParentBinding(pickerTextBox, TextBox.SizeTypeProperty, InfoPickerInput.SizeTypeProperty);
CreateTemplateParentBinding(pickerTextBox, TextBox.IsReadOnlyProperty,
+63 -47
View File
@@ -1,13 +1,13 @@
using AtomUI.Data;
using System.Reactive.Disposables;
using AtomUI.Data;
using AtomUI.Theme;
using AtomUI.Theme.Data;
using AtomUI.Theme.Styling;
using AtomUI.Utils;
using Avalonia;
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Input;
@@ -29,14 +29,15 @@ public class NavMenuItemClickEventArgs : RoutedEventArgs
}
[PseudoClasses(InlineModePC, HorizontalModePC, VerticalModePC)]
public class NavMenu : NavMenuBase
public class NavMenu : NavMenuBase,
ITokenResourceConsumer
{
public const string InlineModePC = ":inline-mode";
public const string HorizontalModePC = ":horizontal-mode";
public const string VerticalModePC = ":vertical-mode";
public const string DarkStylePC = ":dark";
public const string LightStylePC = ":light";
#region 公共属性定义
/// <summary>
@@ -44,41 +45,41 @@ public class NavMenu : NavMenuBase
/// </summary>
public static readonly StyledProperty<NavMenuMode> ModeProperty =
AvaloniaProperty.Register<NavMenu, NavMenuMode>(nameof(Mode), NavMenuMode.Horizontal);
public static readonly StyledProperty<bool> IsDarkStyleProperty =
AvaloniaProperty.Register<NavMenu, bool>(nameof(IsDarkStyle), false);
public static readonly StyledProperty<double> ActiveBarWidthProperty =
AvaloniaProperty.Register<NavMenu, double>(nameof(ActiveBarWidth), 1.0d,
coerce: (o, v) => Math.Max(Math.Min(v, 1.0), 0.0));
public static readonly StyledProperty<double> ActiveBarHeightProperty =
AvaloniaProperty.Register<NavMenu, double>(nameof(ActiveBarHeight));
public NavMenuMode Mode
{
get => GetValue(ModeProperty);
set => SetValue(ModeProperty, value);
}
public bool IsDarkStyle
{
get => GetValue(IsDarkStyleProperty);
set => SetValue(IsDarkStyleProperty, value);
}
public double ActiveBarWidth
{
get => GetValue(ActiveBarWidthProperty);
set => SetValue(ActiveBarWidthProperty, value);
}
public double ActiveBarHeight
{
get => GetValue(ActiveBarHeightProperty);
set => SetValue(ActiveBarHeightProperty, value);
}
#endregion
#region 公共事件定义
@@ -87,7 +88,7 @@ public class NavMenu : NavMenuBase
RoutedEvent.Register<NavMenu, NavMenuItemClickEventArgs>(
nameof(NavMenuItemClick),
RoutingStrategies.Bubble);
public event EventHandler<NavMenuItemClickEventArgs>? NavMenuItemClick
{
add => AddHandler(NavMenuItemClickEvent, value);
@@ -100,15 +101,15 @@ public class NavMenu : NavMenuBase
internal static readonly StyledProperty<double> HorizontalBorderThicknessProperty =
AvaloniaProperty.Register<NavMenuItem, double>(nameof(HorizontalBorderThickness));
public double HorizontalBorderThickness
{
get => GetValue(HorizontalBorderThicknessProperty);
set => SetValue(HorizontalBorderThicknessProperty, value);
}
#endregion
private static readonly FuncTemplate<Panel?> DefaultPanel =
new(() => new StackPanel { Orientation = Orientation.Vertical });
@@ -122,7 +123,9 @@ public class NavMenu : NavMenuBase
AutomationProperties.ControlTypeOverrideProperty.OverrideDefaultValue<NavMenu>(AutomationControlType.Menu);
}
private bool _initialized;
private CompositeDisposable? _tokenBindingsDisposable;
CompositeDisposable? ITokenResourceConsumer.TokenBindingsDisposable => _tokenBindingsDisposable;
public NavMenu()
{
@@ -176,6 +179,7 @@ public class NavMenu : NavMenuBase
{
UpdatePseudoClasses();
}
if (change.Property == ModeProperty)
{
if (VisualRoot is not null)
@@ -185,16 +189,18 @@ public class NavMenu : NavMenuBase
}
}
}
private void SetupControlTheme()
{
if (Mode == NavMenuMode.Horizontal)
{
TokenResourceBinder.CreateTokenBinding(this, ThemeProperty, HorizontalNavMenuTheme.ID);
this.AddTokenBindingDisposable(
TokenResourceBinder.CreateTokenBinding(this, ThemeProperty, HorizontalNavMenuTheme.ID));
}
else
{
TokenResourceBinder.CreateTokenBinding(this, ThemeProperty, VerticalNavMenuTheme.ID);
this.AddTokenBindingDisposable(
TokenResourceBinder.CreateTokenBinding(this, ThemeProperty, VerticalNavMenuTheme.ID));
}
}
@@ -221,15 +227,15 @@ public class NavMenu : NavMenuBase
if (Mode == NavMenuMode.Horizontal)
{
BindUtils.RelayBind(this, ActiveBarHeightProperty, navMenuItem, NavMenuItem.ActiveBarHeightProperty);
BindUtils.RelayBind(this, ActiveBarWidthProperty, navMenuItem, NavMenuItem.ActiveBarWidthProperty);
BindUtils.RelayBind(this, ActiveBarWidthProperty, navMenuItem, NavMenuItem.ActiveBarWidthProperty);
}
BindUtils.RelayBind(this, ModeProperty, navMenuItem, NavMenuItem.ModeProperty);
BindUtils.RelayBind(this, IsDarkStyleProperty, navMenuItem, NavMenuItem.IsDarkStyleProperty);
BindUtils.RelayBind(this, IsMotionEnabledProperty, navMenuItem, NavMenuItem.IsMotionEnabledProperty);
}
}
private void UpdatePseudoClasses()
{
PseudoClasses.Set(HorizontalModePC, Mode == NavMenuMode.Horizontal);
@@ -238,47 +244,52 @@ public class NavMenu : NavMenuBase
PseudoClasses.Set(DarkStylePC, IsDarkStyle);
PseudoClasses.Set(LightStylePC, !IsDarkStyle);
}
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
if (!_initialized)
{
SetupControlTheme();
SetupItemContainerTheme();
SetupInteractionHandler();
_initialized = true;
}
_tokenBindingsDisposable ??= new CompositeDisposable();
this.AddTokenBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, HorizontalBorderThicknessProperty,
SharedTokenKey.LineWidth,
BindingPriority.Template,
new RenderScaleAwareDoubleConfigure(this)));
this.AddTokenBindingDisposable(
TokenResourceBinder.CreateTokenBinding(this, ActiveBarWidthProperty, NavMenuTokenKey.ActiveBarWidth));
this.AddTokenBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, ActiveBarHeightProperty,
NavMenuTokenKey.ActiveBarHeight));
SetupControlTheme();
SetupItemContainerTheme();
SetupInteractionHandler();
}
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnDetachedFromLogicalTree(e);
this.DisposeTokenBindings();
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
InteractionHandler?.Attach(this);
TokenResourceBinder.CreateTokenBinding(this, HorizontalBorderThicknessProperty, SharedTokenKey.LineWidth,
BindingPriority.Template,
new RenderScaleAwareDoubleConfigure(this));
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
InteractionHandler?.Detach(this);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
TokenResourceBinder.CreateTokenBinding(this, ActiveBarWidthProperty, NavMenuTokenKey.ActiveBarWidth);
TokenResourceBinder.CreateTokenBinding(this, ActiveBarHeightProperty, NavMenuTokenKey.ActiveBarHeight);
}
private void SetupInteractionHandler(bool needMount = false)
{
if (needMount)
{
InteractionHandler?.Detach(this);
}
if (Mode == NavMenuMode.Inline)
{
InteractionHandler = new InlineNavMenuInteractionHandler();
@@ -287,6 +298,7 @@ public class NavMenu : NavMenuBase
{
InteractionHandler = new DefaultNavMenuInteractionHandler();
}
if (needMount)
{
InteractionHandler?.Attach(this);
@@ -297,7 +309,7 @@ public class NavMenu : NavMenuBase
{
if (ItemContainerTheme is null || force)
{
string resourceKey;
string resourceKey;
if (Mode == NavMenuMode.Vertical)
{
resourceKey = VerticalNavMenuItemTheme.ID;
@@ -310,7 +322,9 @@ public class NavMenu : NavMenuBase
{
resourceKey = TopLevelHorizontalNavMenuItemTheme.ID;
}
TokenResourceBinder.CreateGlobalResourceBinding(this, ItemContainerThemeProperty, resourceKey);
this.AddTokenBindingDisposable(
TokenResourceBinder.CreateGlobalResourceBinding(this, ItemContainerThemeProperty, resourceKey));
}
}
@@ -331,6 +345,7 @@ public class NavMenu : NavMenuBase
{
item.IsSelected = false;
}
foreach (var childItem in item.Items)
{
if (childItem is NavMenuItem navMenuItem)
@@ -370,7 +385,7 @@ public class NavMenu : NavMenuBase
}
}
}
private void CloseInlineItemRecursively(NavMenuItem navMenuItem)
{
foreach (var item in navMenuItem.Items)
@@ -380,10 +395,11 @@ public class NavMenu : NavMenuBase
CloseInlineItemRecursively(childNavMenuItem);
}
}
navMenuItem.CloseInlineItem();
navMenuItem.IsSubMenuOpen = false;
}
internal void RaiseNavMenuItemClick(INavMenuItem navMenuItem)
{
RaiseEvent(new NavMenuItemClickEventArgs(NavMenuItemClickEvent, navMenuItem));
@@ -66,7 +66,8 @@ internal class NumericUpDownTheme : BaseControlTheme
AcceptsReturn = false,
EmbedMode = true
};
BindUtils.RelayBind(numericUpDown, DataValidationErrors.ErrorsProperty, textBox, DataValidationErrors.ErrorsProperty);
CreateTemplateParentBinding(textBox, DataValidationErrors.ErrorsProperty, DataValidationErrors.ErrorsProperty);
CreateTemplateParentBinding(textBox, TextBox.SizeTypeProperty, NumericUpDown.SizeTypeProperty);
CreateTemplateParentBinding(textBox, Avalonia.Controls.TextBox.IsReadOnlyProperty,
Avalonia.Controls.NumericUpDown.IsReadOnlyProperty);
@@ -0,0 +1,29 @@
using System.Diagnostics;
using System.Reactive.Disposables;
using Avalonia;
namespace AtomUI.Theme;
public interface ITokenResourceConsumer
{
CompositeDisposable? TokenBindingsDisposable { get; }
}
public static class StyledElementTokenBindingsExtensions
{
public static void AddTokenBindingDisposable(this StyledElement control, IDisposable tokenBindingsDisposable)
{
var consumer = control as ITokenResourceConsumer;
Debug.Assert(consumer != null, $"{control.GetType()} is not ITokenResourceConsumer");
Debug.Assert(consumer.TokenBindingsDisposable != null,
$"The TokenBindingsDisposable of ITokenResourceConsumer {control.GetType()} is null.");
consumer.TokenBindingsDisposable.Add(tokenBindingsDisposable);
}
public static void DisposeTokenBindings(this StyledElement control)
{
var consumer = control as ITokenResourceConsumer;
Debug.Assert(consumer != null, $"{control.GetType()} is not ITokenResourceConsumer");
consumer.TokenBindingsDisposable?.Dispose();
}
}