Browse Source

Added TextSelector and AutoCompleteMode properties to the AutoCompleteBox

Now it's possible to change the logic for modifying the text of the control after choosing the autocomplete option
pull/4685/head
Kir-Antipov 6 years ago
parent
commit
5bf12ac0f0
  1. 222
      src/Avalonia.Controls/AutoCompleteBox.cs

222
src/Avalonia.Controls/AutoCompleteBox.cs

@ -225,6 +225,52 @@ namespace Avalonia.Controls
Custom = 13,
}
/// <summary>
/// Represents the selector used by the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control to
/// determine how the specified text should be modified with an item.
/// </summary>
/// <returns>
/// Modified text that will be used by the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" />.
/// </returns>
/// <param name="search">The string used as the basis for filtering.</param>
/// <param name="item">
/// The selected item that should be combined with the
/// <paramref name="search" /> parameter.
/// </param>
/// <typeparam name="T">
/// The type used for filtering the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" />.
/// At the moment this type known only as a string.
/// </typeparam>
public delegate string AutoCompleteSelector<T>(string search, T item);
/// <summary>
/// Specifies how the selected autocomplete result should be treated.
/// </summary>
public enum AutoCompleteMode
{
/// <summary>
/// Specifies that the text will be replaced
/// with the selected autocomplete result.
/// </summary>
Replace = 0,
/// <summary>
/// Specifies that the selected autocomplete result
/// will be appended to the text.
/// </summary>
Append = 1,
/// <summary>
/// Specifies that a custom selector is used. This mode is used when
/// the <see cref="P:Avalonia.Controls.AutoCompleteBox.TextSelector"/>
/// property is set.
/// </summary>
Custom = 2
}
/// <summary>
/// Represents a control that provides a text box for user input and a
/// drop-down that contains possible matches based on the input in the text
@ -362,6 +408,8 @@ namespace Avalonia.Controls
private AutoCompleteFilterPredicate<object> _itemFilter;
private AutoCompleteFilterPredicate<string> _textFilter = AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith);
private AutoCompleteSelector<string> _textSelector = AutoCompleteSelection.GetSelector(AutoCompleteMode.Replace);
public static readonly RoutedEvent<SelectionChangedEventArgs> SelectionChangedEvent =
RoutedEvent.Register<SelectionChangedEventArgs>(nameof(SelectionChanged), RoutingStrategies.Bubble, typeof(AutoCompleteBox));
@ -499,6 +547,17 @@ namespace Avalonia.Controls
defaultValue: AutoCompleteFilterMode.StartsWith,
validate: IsValidFilterMode);
/// <summary>
/// Gets the identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.AutoCompleteMode" />
/// dependency property.
/// </summary>
public static readonly StyledProperty<AutoCompleteMode> AutoCompleteModeProperty =
AvaloniaProperty.Register<AutoCompleteBox, AutoCompleteMode>(
nameof(AutoCompleteMode),
defaultValue: AutoCompleteMode.Replace,
validate: IsValidAutoCompleteMode);
/// <summary>
/// Identifies the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemFilter" />
@ -528,6 +587,21 @@ namespace Avalonia.Controls
(o, v) => o.TextFilter = v,
unsetValue: AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith));
/// <summary>
/// Identifies the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.TextSelector" />
/// dependency property.
/// </summary>
/// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.TextSelector" />
/// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, AutoCompleteSelector<string>> TextSelectorProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteSelector<string>>(
nameof(TextSelector),
o => o.TextSelector,
(o, v) => o.TextSelector = v,
unsetValue: AutoCompleteSelection.GetSelector(AutoCompleteMode.Replace));
/// <summary>
/// Identifies the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />
@ -578,6 +652,19 @@ namespace Avalonia.Controls
}
}
private static bool IsValidAutoCompleteMode(AutoCompleteMode mode)
{
switch (mode)
{
case AutoCompleteMode.Replace:
case AutoCompleteMode.Append:
case AutoCompleteMode.Custom:
return true;
default:
return false;
}
}
/// <summary>
/// Handle the change of the IsEnabled property.
/// </summary>
@ -728,6 +815,19 @@ namespace Avalonia.Controls
TextFilter = AutoCompleteSearch.GetFilter(mode);
}
/// <summary>
/// AutoCompleteModeProperty property changed handler.
/// </summary>
/// <param name="e">Event arguments.</param>
private void OnAutoCompleteModePropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
AutoCompleteMode mode = (AutoCompleteMode)e.NewValue;
// Sets the text selector for the new value
if (mode != AutoCompleteMode.Custom)
TextSelector = AutoCompleteSelection.GetSelector(mode);
}
/// <summary>
/// ItemFilterProperty property changed handler.
/// </summary>
@ -748,6 +848,25 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// TextSelectorProperty property changed handler.
/// </summary>
/// <param name="e">Event arguments.</param>
private void OnTextSelectorPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
AutoCompleteSelector<string> value = e.NewValue as AutoCompleteSelector<string>;
// If null, revert to the "Replace" predicate
if (value == null)
{
AutoCompleteMode = AutoCompleteMode.Replace;
}
else if (value.Method.DeclaringType != typeof(AutoCompleteSelection))
{
AutoCompleteMode = AutoCompleteMode.Custom;
}
}
/// <summary>
/// ItemsSourceProperty property changed handler.
/// </summary>
@ -793,6 +912,8 @@ namespace Avalonia.Controls
SearchTextProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnSearchTextPropertyChanged(e));
FilterModeProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnFilterModePropertyChanged(e));
ItemFilterProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnItemFilterPropertyChanged(e));
AutoCompleteModeProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnAutoCompleteModePropertyChanged(e));
TextSelectorProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnTextSelectorPropertyChanged(e));
ItemsProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnItemsPropertyChanged(e));
IsEnabledProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnControlIsEnabledChanged(e));
}
@ -1015,6 +1136,31 @@ namespace Avalonia.Controls
set { SetValue(FilterModeProperty, value); }
}
/// <summary>
/// Gets or sets how the text in the text box will be modified
/// with the selected autocomplete item.
/// </summary>
/// <value>
/// One of the <see cref="T:Avalonia.Controls.AutoCompleteMode" />
/// values. The default is
/// <see cref="F:Avalonia.Controls.AutoCompleteMode.Replace" />.</value>
/// <exception cref="T:System.ArgumentException">
/// The specified value is not a valid
/// <see cref="T:Avalonia.Controls.AutoCompleteMode" />.
/// </exception>
/// <remarks>
/// Use the AutoCompleteMode property to specify the way the text will
/// be modified with the selected autocomplete item. For example, text
/// can be modified in a predefined or custom way. The autocomplete
/// mode is automatically set to Custom if you set the TextSelector
/// property.
/// </remarks>
public AutoCompleteMode AutoCompleteMode
{
get { return GetValue(AutoCompleteModeProperty); }
set { SetValue(AutoCompleteModeProperty, value); }
}
public string Watermark
{
get { return GetValue(WatermarkProperty); }
@ -1061,6 +1207,26 @@ namespace Avalonia.Controls
set { SetAndRaise(TextFilterProperty, ref _textFilter, value); }
}
/// <summary>
/// Gets or sets the custom method that combines the user-entered
/// text to and one of the items specified by the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />.
/// </summary>
/// <value>
/// The custom method that combines the user-entered
/// text to and one of the items specified by the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />.
/// </value>
/// <remarks>
/// The AutoCompleteMode is automatically set to Custom if you set
/// the TextSelector property.
/// </remarks>
public AutoCompleteSelector<string> TextSelector
{
get { return _textSelector; }
set { SetAndRaise(TextSelectorProperty, ref _textSelector, value); }
}
public Func<string, CancellationToken, Task<IEnumerable<object>>> AsyncPopulator
{
get { return _asyncPopulator; }
@ -2331,7 +2497,7 @@ namespace Avalonia.Controls
}
else
{
text = FormatValue(newItem, true);
text = TextSelector(SearchText, FormatValue(newItem, true));
}
// Update the Text property and the TextBox values
@ -2590,6 +2756,60 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// A predefined set of selector functions for the known, built-in
/// AutoCompleteMode enumeration values.
/// </summary>
private static class AutoCompleteSelection
{
/// <summary>
/// Index function that retrieves the selector for the provided
/// AutoCompleteMode.
/// </summary>
/// <param name="completeMode">The built-in autocomplete mode.</param>
/// <returns>Returns the string-based selector function.</returns>
public static AutoCompleteSelector<string> GetSelector(AutoCompleteMode completeMode)
{
switch (completeMode)
{
case AutoCompleteMode.Replace:
return Replace;
case AutoCompleteMode.Append:
return Append;
case AutoCompleteMode.Custom:
default:
return null;
}
}
/// <summary>
/// Implements AutoCompleteMode.Replace.
/// </summary>
/// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param>
/// <returns>
/// Return the <paramref name="value"/> and ignores the
/// <paramref name="text"/>.
/// </returns>
private static string Replace(string text, string value)
{
return value ?? String.Empty;
}
/// <summary>
/// Implements AutoCompleteMode.Append.
/// </summary>
/// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param>
/// <returns>
/// Returns the concatenated string.
/// </returns>
private static string Append(string text, string value)
{
return text + value;
}
}
/// <summary>
/// A framework element that permits a binding to be evaluated in a new data
/// context leaf node.

Loading…
Cancel
Save