mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-27 21:58:05 +08:00
Add ITokenResourceConsumer
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using AtomUI.Data;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user