diff --git a/samples/BehaviorsTestApplication/Controls/SingleSelectionTabControl.cs b/samples/BehaviorsTestApplication/Controls/SingleSelectionTabControl.cs new file mode 100644 index 000000000..5e42fd6aa --- /dev/null +++ b/samples/BehaviorsTestApplication/Controls/SingleSelectionTabControl.cs @@ -0,0 +1,14 @@ +using System; +using Avalonia.Controls; + +namespace BehaviorsTestApplication.Controls; + +public class SingleSelectionTabControl : TabControl +{ + protected override Type StyleKeyOverride => typeof(TabControl); + + static SingleSelectionTabControl() + { + SelectionModeProperty.OverrideDefaultValue(SelectionMode.Single); + } +} diff --git a/samples/BehaviorsTestApplication/Views/MainView.axaml b/samples/BehaviorsTestApplication/Views/MainView.axaml index e41a046dc..a4ed52057 100644 --- a/samples/BehaviorsTestApplication/Views/MainView.axaml +++ b/samples/BehaviorsTestApplication/Views/MainView.axaml @@ -13,17 +13,20 @@ - - + + + + @@ -150,6 +153,6 @@ - + diff --git a/samples/BehaviorsTestApplication/Views/MainView.axaml.cs b/samples/BehaviorsTestApplication/Views/MainView.axaml.cs index 988073e86..61441b7c4 100644 --- a/samples/BehaviorsTestApplication/Views/MainView.axaml.cs +++ b/samples/BehaviorsTestApplication/Views/MainView.axaml.cs @@ -1,5 +1,4 @@ -using Avalonia.Controls; -using System.Linq; +using Avalonia.Controls; namespace BehaviorsTestApplication.Views; @@ -9,28 +8,4 @@ public MainView() { InitializeComponent(); } - - private void OnSearchTextChanged(object? sender, Avalonia.Interactivity.RoutedEventArgs e) - { - var query = SearchBox.Text?.ToLowerInvariant() ?? string.Empty; - var visibleCount = 0; - - var tabItems = PagesTabControl.Items.OfType().ToList(); - - foreach (var item in tabItems) - { - var header = item.Header?.ToString()?.ToLowerInvariant() ?? string.Empty; - var visible = header.Contains(query); - item.IsVisible = visible; - - if (visible) - { - visibleCount++; - } - } - - PagesTabControl.SelectedItem = tabItems.FirstOrDefault(x => x.IsVisible); - - NoMatchesText.IsVisible = visibleCount == 0; - } } diff --git a/src/Avalonia.Xaml.Interactions.Custom/SelectingItemsControl/SelectingItemsControlSearchBehavior.cs b/src/Avalonia.Xaml.Interactions.Custom/SelectingItemsControl/SelectingItemsControlSearchBehavior.cs new file mode 100644 index 000000000..ca29625f4 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/SelectingItemsControl/SelectingItemsControlSearchBehavior.cs @@ -0,0 +1,96 @@ +using System.Linq; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// Filters items based on the text of a search box. +/// +public sealed class SelectingItemsControlSearchBehavior : StyledElementBehavior +{ + /// + /// Identifies the avalonia property. + /// + public static readonly StyledProperty SearchBoxProperty = + AvaloniaProperty.Register(nameof(SearchBox)); + + /// + /// Identifies the avalonia property. + /// + public static readonly StyledProperty NoMatchesControlProperty = + AvaloniaProperty.Register(nameof(NoMatchesControl)); + + /// + /// Gets or sets the search box control. + /// + [ResolveByName] + public TextBox? SearchBox + { + get => GetValue(SearchBoxProperty); + set => SetValue(SearchBoxProperty, value); + } + + /// + /// Gets or sets the control displayed when no matches are found. + /// + [ResolveByName] + public Control? NoMatchesControl + { + get => GetValue(NoMatchesControlProperty); + set => SetValue(NoMatchesControlProperty, value); + } + + /// + protected override void OnAttachedToVisualTree() + { + if (SearchBox is not null) + { + SearchBox.AddHandler(InputElement.TextInputEvent, SearchBox_TextChanged, RoutingStrategies.Bubble); + SearchBox.AddHandler(TextBox.TextChangedEvent, SearchBox_TextChanged, RoutingStrategies.Bubble); + } + } + + /// + protected override void OnDetachedFromVisualTree() + { + if (SearchBox is not null) + { + SearchBox.RemoveHandler(InputElement.TextInputEvent, SearchBox_TextChanged); + SearchBox.RemoveHandler(TextBox.TextChangedEvent, SearchBox_TextChanged); + } + } + + private void SearchBox_TextChanged(object? sender, RoutedEventArgs e) + { + if (AssociatedObject is null) + { + return; + } + + var query = SearchBox?.Text?.ToLowerInvariant() ?? string.Empty; + var visibleCount = 0; + var tabItems = AssociatedObject.Items.OfType().ToList(); + + foreach (var item in tabItems) + { + var header = item.Header?.ToString()?.ToLowerInvariant() ?? string.Empty; + var visible = header.Contains(query); + item.IsVisible = visible; + if (visible) + { + visibleCount++; + } + } + + AssociatedObject.SelectedItem = tabItems.FirstOrDefault(x => x.IsVisible); + + if (NoMatchesControl is not null) + { + NoMatchesControl.IsVisible = visibleCount == 0; + } + } +}