diff --git a/controlgallery/AtomUIGallery.Browser/BrowserGalleryView.cs b/controlgallery/AtomUIGallery.Browser/BrowserGalleryView.cs index 68a849292..b11991a5a 100644 --- a/controlgallery/AtomUIGallery.Browser/BrowserGalleryView.cs +++ b/controlgallery/AtomUIGallery.Browser/BrowserGalleryView.cs @@ -1,5 +1,6 @@ using AtomUIGallery.ShowCases.AboutUs; using AtomUIGallery.ShowCases.Button; +using AtomUIGallery.ShowCases.FloatButton; using AtomUIGallery.ShowCases.Icon; using AtomUIGallery.ShowCases.Palette; using Avalonia; @@ -21,12 +22,14 @@ internal sealed class BrowserGalleryView : UserControl, IScreen private static readonly BrowserGalleryPageKind[] s_pagesToPreload = [ BrowserGalleryPageKind.Button, + BrowserGalleryPageKind.FloatButton, BrowserGalleryPageKind.Palette, BrowserGalleryPageKind.Icons ]; private readonly Border _aboutUsNavigationItem; private readonly Border _buttonNavigationItem; + private readonly Border _floatButtonNavigationItem; private readonly Border _paletteNavigationItem; private readonly Border _iconsNavigationItem; private readonly Grid _contentHost; @@ -72,10 +75,11 @@ internal sealed class BrowserGalleryView : UserControl, IScreen }; Grid.SetColumnSpan(header, 2); - _aboutUsNavigationItem = CreateNavigationItem("AboutUs", () => ShowAboutUs()); - _buttonNavigationItem = CreateNavigationItem("Button", () => ShowButton()); - _paletteNavigationItem = CreateNavigationItem("Palette", () => ShowPalette()); - _iconsNavigationItem = CreateNavigationItem("Icons", () => ShowIcons()); + _aboutUsNavigationItem = CreateNavigationItem("AboutUs", () => ShowAboutUs()); + _buttonNavigationItem = CreateNavigationItem("Button", () => ShowButton()); + _floatButtonNavigationItem = CreateNavigationItem("FloatButton", () => ShowFloatButton()); + _paletteNavigationItem = CreateNavigationItem("Palette", () => ShowPalette()); + _iconsNavigationItem = CreateNavigationItem("Icons", () => ShowIcons()); var navigation = new Border { @@ -97,6 +101,7 @@ internal sealed class BrowserGalleryView : UserControl, IScreen }, _aboutUsNavigationItem, _buttonNavigationItem, + _floatButtonNavigationItem, _paletteNavigationItem, _iconsNavigationItem } @@ -158,6 +163,11 @@ internal sealed class BrowserGalleryView : UserControl, IScreen ShowPage(BrowserGalleryPageKind.Button, _buttonNavigationItem); } + private void ShowFloatButton() + { + ShowPage(BrowserGalleryPageKind.FloatButton, _floatButtonNavigationItem); + } + private void ShowPalette() { ShowPage(BrowserGalleryPageKind.Palette, _paletteNavigationItem); @@ -226,6 +236,10 @@ internal sealed class BrowserGalleryView : UserControl, IScreen { DataContext = new ButtonViewModel(this) }, + BrowserGalleryPageKind.FloatButton => new FloatButtonShowCase + { + DataContext = new FloatButtonViewModel(this) + }, BrowserGalleryPageKind.Palette => new PaletteShowCase { DataContext = new PaletteViewModel(this) @@ -275,6 +289,7 @@ internal sealed class BrowserGalleryView : UserControl, IScreen { ApplyNavigationItemState(_aboutUsNavigationItem, selectedItem == _aboutUsNavigationItem); ApplyNavigationItemState(_buttonNavigationItem, selectedItem == _buttonNavigationItem); + ApplyNavigationItemState(_floatButtonNavigationItem, selectedItem == _floatButtonNavigationItem); ApplyNavigationItemState(_paletteNavigationItem, selectedItem == _paletteNavigationItem); ApplyNavigationItemState(_iconsNavigationItem, selectedItem == _iconsNavigationItem); } @@ -295,6 +310,7 @@ internal sealed class BrowserGalleryView : UserControl, IScreen { AboutUs, Button, + FloatButton, Palette, Icons } diff --git a/docs/AtomUIGallery/browser-gallery-porting-notes.md b/docs/AtomUIGallery/browser-gallery-porting-notes.md index 8dd368f7c..1328e4187 100644 --- a/docs/AtomUIGallery/browser-gallery-porting-notes.md +++ b/docs/AtomUIGallery/browser-gallery-porting-notes.md @@ -6,7 +6,7 @@ - 新增 Browser Gallery 项目并跑通空壳应用。 - Browser 启动阶段使用 AtomUI 红色 SVG logo。 -- Browser Gallery 不复制 `AboutUsPage` / `ButtonShowCase` / `PaletteShowCase` / `IconShowCase`,只做一层薄的宿主封装。 +- Browser Gallery 不复制 `AboutUsPage` / `ButtonShowCase` / `FloatButtonShowCase` / `PaletteShowCase` / `IconShowCase`,只做一层薄的宿主封装。 - Browser 可以引用 `AtomUI.Desktop.Controls`,用户侧继续调用 `UseDesktopControls()`,控件库内部按平台自动降级。 - 不改变公开 API,不影响 Desktop Gallery 原有行为。 @@ -25,6 +25,10 @@ | Button 迁移后 Browser 白屏 | 临时把 Browser 默认页切到 `ButtonShowCase` 时,页面无 `.splash-error` 但 canvas 持续白屏 | `ButtonShowCase` 首次引入 `ShowCasePanel` / `ShowCaseItem` / `Separator` / `OptionButtonGroup`,并且完整 Desktop `ButtonTheme` 在 Browser 首帧下过重且不稳定 | Browser provider 补 `Separator`、`OptionButtonGroup` 主题和 token;`BrowserButtonThemes.axaml` 使用轻量 `atom:Button` 降级主题,但保留 hover/pressed/loading/wave/icon/dashed/ghost 等交互表达,Desktop 仍走完整 `ButtonTheme` | | Browser Button 视觉降级过头 | Button ShowCase 中 dashed、icon-only、Search、Ghost 等区域与 Desktop 正常效果差异明显 | 首版 Browser Button 主题只保留基础状态,缺少 Desktop 的 Frame 高度、icon-only padding/尺寸、DashedBorder 和 Ghost/Danger 组合样式 | 在不恢复完整 Desktop `ButtonTheme` 的前提下,补齐 Browser Button 的关键可见样式;Release host 中验证 Button 和 Ghost 区域正常渲染 | | Link Button 在 Ghost 区域出现白底 | Desktop Gallery 的 Ghost Button 示例里,Link 类型按钮在灰色背景上出现白色背景块 | Desktop `ButtonTheme` 的 `ButtonType=Link` 分支直接给 template `Border#Frame` 设置了 `DefaultBg`,覆盖了按钮自身的透明背景 | 删除 Link 类型对 `Frame.Background` 的白底设置,改为 Link 按钮自身 `Background=Transparent`,让 template binding 正常透传 | +| FloatButton 迁移需要 OverlayLayer | Browser 加入 `FloatButtonShowCase` 后需要让悬浮按钮挂载到正确的局部 overlay | `FloatButtonHost` / `FloatButtonGroupHost` 不依赖 Window,依赖 `ScopeAwareOverlayLayer`;ShowCase 内的 `atom:ScrollViewer` 模板已经提供 `ScopeAwareOverlayLayerPanel` | Browser provider 补 `FloatButton`、`Badge`、`ToggleSwitch` 主题和 token,继续复用共享 ShowCase,不新增 Browser 专用页面 | +| FloatButtonGroup 存在重复父级风险 | 页面缓存、隐藏/显示或重新套模板后,同一批子按钮可能被再次加入内部 `FloatButtonItemsControl` | `FloatButtonGroupHost` 把 Host `Children` 转移到 overlay 内的 `FloatButtonGroup`,旧 group / items control 没有在 detach 或 re-template 时清理子项;click trigger 在 detach 时也可能重新订阅输入事件 | 内部补齐 group children、items control children 和 items layout children 的成对清理;click trigger 只在已附着视觉树时订阅,detach 时释放 | +| Browser FloatButton Placement 展开缺子按钮 | Placement 示例中点击左侧展开组后,trigger 变为 X,但 X 左侧两个子按钮没有显示 | Browser 分支此前完全跳过 Desktop initialized handler,导致 `MotionTransformOptionsAnimator` 没有注册;`MoveRightInMotion` / `MoveLeftInMotion` 的 `TransformOperations` keyframe 动画停留在隐藏起始态 | initialized handler 所有平台都注册 `TransformOperations` animator;`ToolTipService` 和 `MediaBreakPointThemeBootstrapper` 继续只在 native window 下启用 | +| FloatButton Tooltip 暂未打开 Browser 完整链路 | Tooltip 属性在 Browser 下不会导致页面崩溃,但本轮不验证 tooltip 弹层 | AtomUI Tooltip 会继续牵出 `Popup`、`PopupRoot`、`OverlayPopupHost`、`ArrowDecoratedBox`、`PopupHostToken`、`ToolTipService` 等一组资源,超出 FloatButton ShowCase 首轮接入范围 | 本轮先保证 FloatButton 主体、Badge、BackTop、Group 可用;Tooltip/Popup Browser 降级后续单独拆分验证 | | Browser shell 字体未继承 AtomUI 字体 | Browser Gallery 外壳文字看起来没有使用 AtomUI 的 AlibabaSans | Browser 根是 `UserControl`,没有 Desktop `atom:Window` theme 里的 `FontFamily="{atom:SharedTokenResource FontFamily}"` 继承入口 | `BrowserGalleryView` 根设置 `fonts:AlibabaSans#Alibaba Sans, $Default`,由 Avalonia 可继承 `FontFamily` 向导航外壳和共享 ShowCase 传递 | | Browser 导航切页卡顿明显 | AboutUs / Button / Palette / Icons 之间切换时,新页面出来有明显停顿 | Browser 宿主原先每次点击都 `new` 页面和 ViewModel,并替换 `ContentControl.Content`,导致 ShowCase XAML、控件模板、主题匹配、首次布局和绘制全部冷启动 | `BrowserGalleryView` 改为 lazy page cache,首次进入页面后保留在同一个 `Grid` 中,切换只调整 `IsVisible`;首屏加载后再按 idle 顺序预热 Button / Palette / Icons,降低用户首次点击重页面时的冷启动体感 | @@ -72,6 +76,11 @@ var buttonShowCase = new ButtonShowCase DataContext = new ButtonViewModel(this) }; +var floatButtonShowCase = new FloatButtonShowCase +{ + DataContext = new FloatButtonViewModel(this) +}; + var paletteShowCase = new PaletteShowCase { DataContext = new PaletteViewModel(this) @@ -85,7 +94,7 @@ var iconShowCase = new IconShowCase 页面首次打开后会保留在 Browser 宿主的内容 `Grid` 中,非当前页通过 `IsVisible = false` 隐藏。这样可以保留 ViewModel、控件树、滚动位置和 Icons 已加载内容,避免切回时再次触发 XAML inflate / template / layout 冷启动。 -首屏 `AboutUsPage` 加载完成后,Browser 宿主会用 `DispatcherPriority.ApplicationIdle` 依次预热 `ButtonShowCase`、`PaletteShowCase` 和 `IconShowCase`。预热页面先以 `Opacity = 0`、`IsHitTestVisible = false` 放入内容 `Grid`,让模板和布局在用户空闲时完成一轮,再隐藏回缓存;如果用户在预热期间点击该页面,正常导航会接管可见性。 +首屏 `AboutUsPage` 加载完成后,Browser 宿主会用 `DispatcherPriority.ApplicationIdle` 依次预热 `ButtonShowCase`、`FloatButtonShowCase`、`PaletteShowCase` 和 `IconShowCase`。预热页面先以 `Opacity = 0`、`IsHitTestVisible = false` 放入内容 `Grid`,让模板和布局在用户空闲时完成一轮,再隐藏回缓存;如果用户在预热期间点击该页面,正常导航会接管可见性。 当前 Browser 已接入页面没有后台定时任务;后续迁移有持续订阅或异步任务的 ShowCase 时,需要单独评估隐藏页保持 attached 的成本。 @@ -131,12 +140,15 @@ themeManagerBuilder.AddControlThemesProvider(RuntimePlatform.Features.SupportsNa Browser desktop provider 当前只承载 Browser Gallery 已接入 ShowCase 需要的最小集合: ```text +Badge/Themes/BadgeThemes.axaml Buttons/Themes/BrowserButtonThemes.axaml +FloatButton/Themes/FloatButtonThemes.axaml GroupBox/Themes/GroupBoxTheme.axaml Input/Themes/BrowserInputThemes.axaml OptionButtonGroup/Themes/OptionButtonBoxThemes.axaml ScrollViewer/Themes/ScrollViewerThemes.axaml Separator/Themes/SeparatorTheme.axaml +Switch/Themes/ToggleSwitchThemes.axaml TabControl/Themes/TabControlThemes.axaml ``` @@ -144,7 +156,9 @@ Browser token 当前只注册: ```text AddOnDecoratedBoxToken +BadgeToken ButtonToken +FloatButtonToken GroupBoxToken LineEditToken MenuToken @@ -152,6 +166,7 @@ OptionButtonToken ScrollViewerToken SeparatorToken TabControlToken +ToggleSwitchToken ``` Desktop 下仍然使用完整 `ControlTokenTypePool` 和 `DesktopControlThemesProvider`,并继续注册原有 initialized handler。Browser 下跳过该 handler,避免注册 Window/Tooltip/媒体断点等 native window 相关逻辑。 @@ -176,6 +191,7 @@ Desktop 下仍然使用完整 `ControlTokenTypePool` 和 `DesktopControlThemesPr ```bash dotnet build controlgallery/AtomUIGallery.Browser/AtomUIGallery.Browser.csproj -c Debug +dotnet build controlgallery/AtomUIGallery.Browser/AtomUIGallery.Browser.csproj -c Release dotnet build controlgallery/AtomUIGallery.Desktop/AtomUIGallery.Desktop.csproj -c Debug ``` @@ -184,8 +200,10 @@ dotnet build controlgallery/AtomUIGallery.Desktop/AtomUIGallery.Desktop.csproj - - Browser Debug build 通过。 - Browser Release build 通过。 - Desktop Gallery Debug build 通过。 -- Browser 实跑 `AboutUsPage` / `ButtonShowCase` / `PaletteShowCase` / `IconShowCase` 渲染成功,无 `.splash-error`。 +- Browser 实跑 `AboutUsPage` / `ButtonShowCase` / `FloatButtonShowCase` / `PaletteShowCase` / `IconShowCase` 渲染成功,无 `.splash-error`。 - `ButtonShowCase` 在 Release host 中验证首屏渲染成功,Button hover 状态可见,点击 smoke test 无当前端口错误日志;最终代码仍默认进入 `AboutUsPage`。 +- `FloatButtonShowCase` 在 Release host 中验证首屏渲染成功;切到 Button 后再切回 FloatButton 仍正常渲染;向下滚动到 Placement / Badge / BackTop 区域后渲染正常;点击 Placement click group 后无当前端口错误日志。 +- Browser 修复 `MotionTransformOptionsAnimator` 注册后,Release host 中复测 Placement 左侧展开组,X 左侧两个子按钮正常显示,无当前端口错误日志。 - `IconShowCase` 的 `Outlined` / `Filled` / `Two Tone` tab 均已在 Browser 中切换并渲染图标网格。 - Browser 导航 lazy cache 后,Release host 中执行 Button / Icons / Button / Icons 切换 smoke test,Icons 二次切回仍正常渲染,无当前端口错误日志。 - Browser 导航 idle 预热后,Release host 中等待首屏预热并执行 Button / Palette / Icons 切换 smoke test,最终 Icons 正常渲染,无当前端口错误日志。 @@ -206,6 +224,7 @@ Browser 运行验证时不要只依赖 DOM 文本,因为 Avalonia Browser 页 ## 待继续处理 - `UseDesktopColorPicker()` 和 `UseDesktopDataGrid()` 尚未接入 Browser 降级路径。 -- Browser Gallery 当前只接入 `AboutUsPage`、`ButtonShowCase`、`PaletteShowCase` 和 `IconShowCase`,完整 Workspace / AppView / AppShell 还未实现。 +- Browser Gallery 当前只接入 `AboutUsPage`、`ButtonShowCase`、`FloatButtonShowCase`、`PaletteShowCase` 和 `IconShowCase`,完整 Workspace / AppView / AppShell 还未实现。 +- Tooltip / Popup 的 Browser 降级链路尚未打开;`FloatButtonShowCase` 中 Tooltip 属性本轮只保证不阻塞页面渲染。 - `BrowserDesktopControlThemesProvider` 的范围后续应随着 ShowCase 迁移逐步扩大,并保持最小可用集合。 - `EmbeddableControlRootTheme` 在 Browser 下的精确不兼容点后续可以进一步拆解;当前先通过 Browser provider 排除该资源,保证启动路径稳定。 diff --git a/src/AtomUI.Desktop.Controls/BrowserDesktopControlThemesProvider.axaml b/src/AtomUI.Desktop.Controls/BrowserDesktopControlThemesProvider.axaml index 9b5f94dcf..b00ab00d3 100644 --- a/src/AtomUI.Desktop.Controls/BrowserDesktopControlThemesProvider.axaml +++ b/src/AtomUI.Desktop.Controls/BrowserDesktopControlThemesProvider.axaml @@ -4,13 +4,16 @@ x:Class="AtomUI.Desktop.Controls.BrowserDesktopControlThemesProvider" Id="AtomUI.Desktop.Controls"> + + + diff --git a/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonGroup.cs b/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonGroup.cs index 98eece80c..cea51cf9f 100644 --- a/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonGroup.cs +++ b/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonGroup.cs @@ -211,6 +211,7 @@ public class FloatButtonGroup : TemplatedControl, IMotionAwareControl private bool _showAnimating; private bool _hideAnimating; private bool _closeRequest; + private bool _isAttachedToVisualTree; static FloatButtonGroup() { @@ -291,6 +292,7 @@ public class FloatButtonGroup : TemplatedControl, IMotionAwareControl _triggerButton.PointerEntered -= HandlePointerEntered; _triggerButton.PointerExited -= HandlePointerExited; } + DetachItemsControlChildren(); _itemsControl = e.NameScope.Find("ItemsControl"); _triggerButton = e.NameScope.Find("Trigger"); _motionActor = e.NameScope.Find(BaseMotionActor.MotionActorPart); @@ -334,7 +336,7 @@ public class FloatButtonGroup : TemplatedControl, IMotionAwareControl { foreach (var child in newChildren) { - if (child is FloatButton floatButton) + if (child is AbstractFloatButton floatButton) { NotifyAddItem(floatButton); } @@ -351,9 +353,9 @@ public class FloatButtonGroup : TemplatedControl, IMotionAwareControl case NotifyCollectionChangedAction.Remove: for (var i = 0; i < e.OldItems!.Count; ++i) { - if (e.OldItems[i] is FloatButton floatButton) + if (e.OldItems[i] is AbstractFloatButton floatButton) { - floatButton.SetCurrentValue(FloatButton.IsEmbedModeProperty, false); + floatButton.SetCurrentValue(AbstractFloatButton.IsEmbedModeProperty, false); } } _itemsControl.Children.RemoveRange(e.OldStartingIndex, e.OldItems!.Count); @@ -409,20 +411,21 @@ public class FloatButtonGroup : TemplatedControl, IMotionAwareControl protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); - _clickTriggerDisposable?.Dispose(); - _clickTriggerDisposable = null; + _isAttachedToVisualTree = true; + ConfigureTriggerType(); } protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { base.OnDetachedFromVisualTree(e); - ConfigureTriggerType(); + _isAttachedToVisualTree = false; + DisposeClickTrigger(); } private void ConfigureTriggerType() { - _clickTriggerDisposable?.Dispose(); - if (Trigger == FloatButtonGroupTrigger.Click) + DisposeClickTrigger(); + if (_isAttachedToVisualTree && Trigger == FloatButtonGroupTrigger.Click) { var inputManager = AvaloniaLocator.Current.GetService(typeof(IInputManager)) as IInputManager; _clickTriggerDisposable = inputManager?.Process.Subscribe(HandleMouseClick); @@ -434,6 +437,20 @@ public class FloatButtonGroup : TemplatedControl, IMotionAwareControl } } + private void DisposeClickTrigger() + { + _clickTriggerDisposable?.Dispose(); + _clickTriggerDisposable = null; + } + + private void DetachItemsControlChildren() + { + if (_itemsControl is { Children.Count: > 0 } itemsControl) + { + itemsControl.Children.RemoveRange(0, itemsControl.Children.Count); + } + } + private void HandleMouseClick(RawInputEventArgs args) { if (args is RawPointerEventArgs pointerEventArgs) diff --git a/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonGroupHost.cs b/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonGroupHost.cs index 043abab56..f15151210 100644 --- a/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonGroupHost.cs +++ b/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonGroupHost.cs @@ -172,12 +172,21 @@ public class FloatButtonGroupHost : TemplatedControl, IMotionAwareControl if (FloatButtonGroup != null) { _overlayLayer = ScopeAwareOverlayLayer.FindLayer(this); + DetachFloatButtonGroupChildren(); _overlayLayer?.Children.Remove(FloatButtonGroup); Disposables?.Dispose(); Disposables = null; FloatButtonGroup = null; } } + + private void DetachFloatButtonGroupChildren() + { + if (FloatButtonGroup is { Children.Count: > 0 } floatButtonGroup) + { + floatButtonGroup.Children.RemoveRange(0, floatButtonGroup.Children.Count); + } + } protected virtual FloatButtonGroup NotifyCreateFloatButtonGroup(CompositeDisposable disposables) { diff --git a/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonItemsControl.cs b/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonItemsControl.cs index 56e1e093d..aa9a83972 100644 --- a/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonItemsControl.cs +++ b/src/AtomUI.Desktop.Controls/FloatButton/FloatButtonItemsControl.cs @@ -93,9 +93,18 @@ internal class FloatButtonItemsControl : TemplatedControl protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); + DetachItemsLayoutChildren(); _itemsLayout = e.NameScope.Find("PART_ItemsLayout"); _itemsLayout?.Children.AddRange(Children); } + + private void DetachItemsLayoutChildren() + { + if (_itemsLayout is { Children.Count: > 0 } itemsLayout) + { + itemsLayout.Children.RemoveRange(0, itemsLayout.Children.Count); + } + } protected virtual void NotifyChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e) { diff --git a/src/AtomUI.Desktop.Controls/ThemeManagerBuilderExtensions.cs b/src/AtomUI.Desktop.Controls/ThemeManagerBuilderExtensions.cs index 79f705f2a..c6e153855 100644 --- a/src/AtomUI.Desktop.Controls/ThemeManagerBuilderExtensions.cs +++ b/src/AtomUI.Desktop.Controls/ThemeManagerBuilderExtensions.cs @@ -32,10 +32,7 @@ public static class ThemeManagerBuilderExtensions themeManagerBuilder.AddLanguageProviders(languageProvider); } - if (RuntimePlatform.Features.SupportsNativeWindow) - { - themeManagerBuilder.InitializedHandlers.Add(HandleThemeManagerInitialized); - } + themeManagerBuilder.InitializedHandlers.Add(HandleThemeManagerInitialized); return themeManagerBuilder; } @@ -43,12 +40,16 @@ public static class ThemeManagerBuilderExtensions private static void HandleThemeManagerInitialized(object? sender, EventArgs e) { Animation.RegisterCustomAnimator(); + if (!RuntimePlatform.Features.SupportsNativeWindow) + { + return; + } + var inputManager = AvaloniaLocator.CurrentMutable.GetService(); Debug.Assert(inputManager != null); AvaloniaLocator.CurrentMutable.BindToSelf(new ToolTipService(inputManager)); - if (RuntimePlatform.Features.SupportsNativeWindow && - sender is ThemeManager themeManager) + if (sender is ThemeManager themeManager) { MediaBreakPointThemeBootstrapper.Attach(themeManager); } @@ -59,14 +60,17 @@ public static class ThemeManagerBuilderExtensions return new List { typeof(AddOnDecoratedBoxToken), + typeof(BadgeToken), typeof(ButtonToken), + typeof(FloatButtonToken), typeof(GroupBoxToken), typeof(LineEditToken), typeof(MenuToken), typeof(OptionButtonToken), typeof(ScrollViewerToken), typeof(SeparatorToken), - typeof(TabControlToken) + typeof(TabControlToken), + typeof(ToggleSwitchToken) }; } }