Browse Source

QoL for ControlCatalog: add sidebar search, auto-sort, and default page selection (#20987)

* feat(ControlCatalog): add sidebar search, auto-sort, and default page selection

- Add search TextBox (PART_SearchBox) to HamburgerMenu pane template
  that filters sidebar items by header text (case-insensitive)
- Auto-sort TabItems alphabetically by Header on first load
- Add IsDefaultPage attached property on HamburgerMenu to preselect
  a specific TabItem (set on Buttons page in MainView)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* refactor: replace IsDefaultPage attached property with simple IsSelected

IsSelected on TabItem is sufficient for preselecting a page after
auto-sort. Removes the custom IsDefaultPage attached property.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pull/20994/head
Nikita Tsukanov 6 months ago
committed by GitHub
parent
commit
a01245a784
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      samples/ControlCatalog/MainView.xaml
  2. 68
      samples/SampleControls/HamburgerMenu/HamburgerMenu.cs
  3. 17
      samples/SampleControls/HamburgerMenu/HamburgerMenu.xaml

2
samples/ControlCatalog/MainView.xaml

@ -16,7 +16,7 @@
</Style>
</Grid.Styles>
<controls:HamburgerMenu Name="Sidebar">
<TabItem Header="Composition">
<TabItem Header="Composition" IsSelected="True">
<pages:CompositionPage />
</TabItem>
<TabItem Header="Accelerator">

68
samples/SampleControls/HamburgerMenu/HamburgerMenu.cs

@ -1,4 +1,6 @@
using Avalonia;
using System;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
@ -8,6 +10,8 @@ namespace ControlSamples
public class HamburgerMenu : TabControl
{
private SplitView? _splitView;
private TextBox? _searchBox;
private bool _initialized;
public static readonly StyledProperty<IBrush?> PaneBackgroundProperty =
SplitView.PaneBackgroundProperty.AddOwner<HamburgerMenu>();
@ -41,6 +45,68 @@ namespace ControlSamples
base.OnApplyTemplate(e);
_splitView = e.NameScope.Find<SplitView>("PART_NavigationPane");
_searchBox = e.NameScope.Find<TextBox>("PART_SearchBox");
if (_searchBox is not null)
{
_searchBox.TextChanged += OnSearchTextChanged;
}
}
protected override void OnLoaded(Avalonia.Interactivity.RoutedEventArgs e)
{
base.OnLoaded(e);
if (!_initialized)
{
_initialized = true;
SortItems();
}
}
private void SortItems()
{
var items = Items.OfType<TabItem>().ToList();
var sorted = items.OrderBy(t => t.Header?.ToString() ?? "", StringComparer.OrdinalIgnoreCase).ToList();
// Only reorder if needed
bool needsSort = false;
for (int i = 0; i < items.Count; i++)
{
if (!ReferenceEquals(items[i], sorted[i]))
{
needsSort = true;
break;
}
}
if (needsSort)
{
Items.Clear();
foreach (var item in sorted)
{
Items.Add(item);
}
}
}
private void OnSearchTextChanged(object? sender, TextChangedEventArgs e)
{
var searchText = _searchBox?.Text;
var hasFilter = !string.IsNullOrWhiteSpace(searchText);
foreach (var item in Items.OfType<TabItem>())
{
if (hasFilter)
{
var header = item.Header?.ToString() ?? "";
item.IsVisible = header.Contains(searchText!, StringComparison.OrdinalIgnoreCase);
}
else
{
item.IsVisible = true;
}
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)

17
samples/SampleControls/HamburgerMenu/HamburgerMenu.xaml

@ -175,10 +175,21 @@
OpenPaneLength="{StaticResource PaneExpandWidth}"
PaneBackground="Transparent">
<SplitView.Pane>
<Grid Margin="0,0,1,5" RowDefinitions="Auto, *, Auto">
<Grid Margin="0,0,1,5" RowDefinitions="Auto, Auto, *, Auto">
<Panel Height="{StaticResource HeaderHeight}" />
<TextBox x:Name="PART_SearchBox"
Grid.Row="1"
PlaceholderText="Search…"
Margin="4,0,8,4"
VerticalContentAlignment="Center">
<TextBox.InnerLeftContent>
<PathIcon Width="14" Height="14" Margin="6,0,0,0"
VerticalAlignment="Center"
Data="M10 2.5a7.5 7.5 0 0 1 5.964 12.048l4.743 4.745a1 1 0 0 1-1.32 1.497l-.094-.083-4.745-4.743A7.5 7.5 0 1 1 10 2.5Zm0 2a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11Z" />
</TextBox.InnerLeftContent>
</TextBox>
<ScrollViewer x:Name="PART_ScrollViewer"
Grid.Row="1"
Grid.Row="2"
HorizontalAlignment="Stretch"
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
@ -195,7 +206,7 @@
</ItemsPresenter>
</ScrollViewer>
<Button x:Name="SettingsButton"
Grid.Row="2"
Grid.Row="3"
Theme="{StaticResource NavigationButton}"
Content="Settings"
Flyout="{TemplateBinding (FlyoutBase.AttachedFlyout)}"

Loading…
Cancel
Save