Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ItemsControl.IsTextSearchEnabled #6210

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 0 additions & 69 deletions src/Avalonia.Controls/ComboBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,6 @@ public class ComboBox : SelectingItemsControl
public static readonly StyledProperty<VerticalAlignment> VerticalContentAlignmentProperty =
ContentControl.VerticalContentAlignmentProperty.AddOwner<ComboBox>();

/// <summary>
/// Defines the <see cref="IsTextSearchEnabled"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsTextSearchEnabledProperty =
AvaloniaProperty.Register<ComboBox, bool>(nameof(IsTextSearchEnabled), true);

private string _textSearchTerm = string.Empty;
private DispatcherTimer _textSearchTimer;
private bool _isDropDownOpen;
private Popup _popup;
private object _selectionBoxItem;
Expand Down Expand Up @@ -173,15 +165,6 @@ public VerticalAlignment VerticalContentAlignment
set { SetValue(VerticalContentAlignmentProperty, value); }
}

/// <summary>
/// Gets or sets a value that specifies whether a user can jump to a value by typing.
/// </summary>
public bool IsTextSearchEnabled
{
get { return GetValue(IsTextSearchEnabledProperty); }
set { SetValue(IsTextSearchEnabledProperty, value); }
}

/// <inheritdoc/>
protected override IItemContainerGenerator CreateItemContainerGenerator()
{
Expand Down Expand Up @@ -247,32 +230,6 @@ protected override void OnKeyDown(KeyEventArgs e)
}
}

/// <inheritdoc />
protected override void OnTextInput(TextInputEventArgs e)
{
if (!IsTextSearchEnabled || e.Handled)
return;

StopTextSearchTimer();

_textSearchTerm += e.Text;

bool match(ItemContainerInfo info) =>
info.ContainerControl is IContentControl control &&
control.Content?.ToString()?.StartsWith(_textSearchTerm, StringComparison.OrdinalIgnoreCase) == true;

var info = ItemContainerGenerator.Containers.FirstOrDefault(match);

if (info != null)
{
SelectedIndex = info.Index;
}

StartTextSearchTimer();

e.Handled = true;
}

/// <inheritdoc/>
protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
{
Expand Down Expand Up @@ -470,31 +427,5 @@ private void SelectPrev()

SelectedIndex = prev;
}

private void StartTextSearchTimer()
{
_textSearchTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
_textSearchTimer.Tick += TextSearchTimer_Tick;
_textSearchTimer.Start();
}

private void StopTextSearchTimer()
{
if (_textSearchTimer == null)
{
return;
}

_textSearchTimer.Stop();
_textSearchTimer.Tick -= TextSearchTimer_Tick;

_textSearchTimer = null;
}

private void TextSearchTimer_Tick(object sender, EventArgs e)
{
_textSearchTerm = string.Empty;
StopTextSearchTimer();
}
}
}
75 changes: 75 additions & 0 deletions src/Avalonia.Controls/ItemsControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using Avalonia.Collections;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Metadata;
Expand All @@ -12,6 +13,7 @@
using Avalonia.Input;
using Avalonia.LogicalTree;
using Avalonia.Metadata;
using Avalonia.Threading;
using Avalonia.VisualTree;

namespace Avalonia.Controls
Expand Down Expand Up @@ -52,6 +54,14 @@ public class ItemsControl : TemplatedControl, IItemsPresenterHost, ICollectionCh
public static readonly StyledProperty<IDataTemplate> ItemTemplateProperty =
AvaloniaProperty.Register<ItemsControl, IDataTemplate>(nameof(ItemTemplate));

/// <summary>
/// Defines the <see cref="IsTextSearchEnabled"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsTextSearchEnabledProperty =
AvaloniaProperty.Register<ItemsControl, bool>(nameof(IsTextSearchEnabled), true);

private string _textSearchTerm = string.Empty;
private DispatcherTimer _textSearchTimer;
private IEnumerable _items = new AvaloniaList<object>();
private int _itemCount;
private IItemContainerGenerator _itemContainerGenerator;
Expand Down Expand Up @@ -135,6 +145,15 @@ public IDataTemplate ItemTemplate
set { SetValue(ItemTemplateProperty, value); }
}

/// <summary>
/// Gets or sets a value that specifies whether a user can jump to a value by typing.
/// </summary>
public bool IsTextSearchEnabled
{
get { return GetValue(IsTextSearchEnabledProperty); }
set { SetValue(IsTextSearchEnabledProperty, value); }
}

/// <summary>
/// Gets the items presenter control.
/// </summary>
Expand Down Expand Up @@ -323,6 +342,36 @@ protected override void OnKeyDown(KeyEventArgs e)
base.OnKeyDown(e);
}

protected override void OnTextInput(TextInputEventArgs e)
{
if (!e.Handled && this is SelectingItemsControl selectingItemsControl)
Royce551 marked this conversation as resolved.
Show resolved Hide resolved
{
if (!IsTextSearchEnabled)
return;

StopTextSearchTimer();

_textSearchTerm += e.Text;

bool match(ItemContainerInfo info) =>
info.ContainerControl is IContentControl control &&
control.Content?.ToString()?.StartsWith(_textSearchTerm, StringComparison.OrdinalIgnoreCase) == true;

var info = ItemContainerGenerator.Containers.FirstOrDefault(match);

if (info != null)
{
selectingItemsControl.SelectedIndex = info.Index;
}

StartTextSearchTimer();

e.Handled = true;
}

base.OnTextInput(e);
}

protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
Expand Down Expand Up @@ -456,6 +505,32 @@ private void ItemTemplateChanged(AvaloniaPropertyChangedEventArgs e)
}
}

private void StartTextSearchTimer()
{
_textSearchTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
_textSearchTimer.Tick += TextSearchTimer_Tick;
_textSearchTimer.Start();
}

private void StopTextSearchTimer()
{
if (_textSearchTimer == null)
{
return;
}

_textSearchTimer.Stop();
_textSearchTimer.Tick -= TextSearchTimer_Tick;

_textSearchTimer = null;
}

private void TextSearchTimer_Tick(object sender, EventArgs e)
{
_textSearchTerm = string.Empty;
StopTextSearchTimer();
}

private void UpdateItemCount()
{
if (Items == null)
Expand Down