diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs
index c164f282e8..16b7d09e8a 100644
--- a/src/Avalonia.Controls/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox.cs
@@ -225,6 +225,52 @@ namespace Avalonia.Controls
Custom = 13,
}
+ ///
+ /// Represents the selector used by the
+ /// control to
+ /// determine how the specified text should be modified with an item.
+ ///
+ ///
+ /// Modified text that will be used by the
+ /// .
+ ///
+ /// The string used as the basis for filtering.
+ ///
+ /// The selected item that should be combined with the
+ /// parameter.
+ ///
+ ///
+ /// The type used for filtering the
+ /// .
+ /// At the moment this type known only as a string.
+ ///
+ public delegate string AutoCompleteSelector(string search, T item);
+
+ ///
+ /// Specifies how the selected autocomplete result should be treated.
+ ///
+ public enum AutoCompleteMode
+ {
+ ///
+ /// Specifies that the text will be replaced
+ /// with the selected autocomplete result.
+ ///
+ Replace = 0,
+
+ ///
+ /// Specifies that the selected autocomplete result
+ /// will be appended to the text.
+ ///
+ Append = 1,
+
+ ///
+ /// Specifies that a custom selector is used. This mode is used when
+ /// the
+ /// property is set.
+ ///
+ Custom = 2
+ }
+
///
/// 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 _itemFilter;
private AutoCompleteFilterPredicate _textFilter = AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith);
+ private AutoCompleteSelector _textSelector = AutoCompleteSelection.GetSelector(AutoCompleteMode.Replace);
+
public static readonly RoutedEvent SelectionChangedEvent =
RoutedEvent.Register(nameof(SelectionChanged), RoutingStrategies.Bubble, typeof(AutoCompleteBox));
@@ -499,6 +547,17 @@ namespace Avalonia.Controls
defaultValue: AutoCompleteFilterMode.StartsWith,
validate: IsValidFilterMode);
+ ///
+ /// Gets the identifier for the
+ ///
+ /// dependency property.
+ ///
+ public static readonly StyledProperty AutoCompleteModeProperty =
+ AvaloniaProperty.Register(
+ nameof(AutoCompleteMode),
+ defaultValue: AutoCompleteMode.Replace,
+ validate: IsValidAutoCompleteMode);
+
///
/// Identifies the
///
@@ -528,6 +587,21 @@ namespace Avalonia.Controls
(o, v) => o.TextFilter = v,
unsetValue: AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith));
+ ///
+ /// Identifies the
+ ///
+ /// dependency property.
+ ///
+ /// The identifier for the
+ ///
+ /// dependency property.
+ public static readonly DirectProperty> TextSelectorProperty =
+ AvaloniaProperty.RegisterDirect>(
+ nameof(TextSelector),
+ o => o.TextSelector,
+ (o, v) => o.TextSelector = v,
+ unsetValue: AutoCompleteSelection.GetSelector(AutoCompleteMode.Replace));
+
///
/// Identifies the
///
@@ -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;
+ }
+ }
+
///
/// Handle the change of the IsEnabled property.
///
@@ -728,6 +815,19 @@ namespace Avalonia.Controls
TextFilter = AutoCompleteSearch.GetFilter(mode);
}
+ ///
+ /// AutoCompleteModeProperty property changed handler.
+ ///
+ /// Event arguments.
+ 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);
+ }
+
///
/// ItemFilterProperty property changed handler.
///
@@ -748,6 +848,25 @@ namespace Avalonia.Controls
}
}
+ ///
+ /// TextSelectorProperty property changed handler.
+ ///
+ /// Event arguments.
+ private void OnTextSelectorPropertyChanged(AvaloniaPropertyChangedEventArgs e)
+ {
+ AutoCompleteSelector value = e.NewValue as AutoCompleteSelector;
+
+ // If null, revert to the "Replace" predicate
+ if (value == null)
+ {
+ AutoCompleteMode = AutoCompleteMode.Replace;
+ }
+ else if (value.Method.DeclaringType != typeof(AutoCompleteSelection))
+ {
+ AutoCompleteMode = AutoCompleteMode.Custom;
+ }
+ }
+
///
/// ItemsSourceProperty property changed handler.
///
@@ -793,6 +912,8 @@ namespace Avalonia.Controls
SearchTextProperty.Changed.AddClassHandler((x,e) => x.OnSearchTextPropertyChanged(e));
FilterModeProperty.Changed.AddClassHandler((x,e) => x.OnFilterModePropertyChanged(e));
ItemFilterProperty.Changed.AddClassHandler((x,e) => x.OnItemFilterPropertyChanged(e));
+ AutoCompleteModeProperty.Changed.AddClassHandler((x,e) => x.OnAutoCompleteModePropertyChanged(e));
+ TextSelectorProperty.Changed.AddClassHandler((x,e) => x.OnTextSelectorPropertyChanged(e));
ItemsProperty.Changed.AddClassHandler((x,e) => x.OnItemsPropertyChanged(e));
IsEnabledProperty.Changed.AddClassHandler((x,e) => x.OnControlIsEnabledChanged(e));
}
@@ -1015,6 +1136,31 @@ namespace Avalonia.Controls
set { SetValue(FilterModeProperty, value); }
}
+ ///
+ /// Gets or sets how the text in the text box will be modified
+ /// with the selected autocomplete item.
+ ///
+ ///
+ /// One of the
+ /// values. The default is
+ /// .
+ ///
+ /// The specified value is not a valid
+ /// .
+ ///
+ ///
+ /// 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.
+ ///
+ 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); }
}
+ ///
+ /// Gets or sets the custom method that combines the user-entered
+ /// text to and one of the items specified by the
+ /// .
+ ///
+ ///
+ /// The custom method that combines the user-entered
+ /// text to and one of the items specified by the
+ /// .
+ ///
+ ///
+ /// The AutoCompleteMode is automatically set to Custom if you set
+ /// the TextSelector property.
+ ///
+ public AutoCompleteSelector TextSelector
+ {
+ get { return _textSelector; }
+ set { SetAndRaise(TextSelectorProperty, ref _textSelector, value); }
+ }
+
public Func>> 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
}
}
+ ///
+ /// A predefined set of selector functions for the known, built-in
+ /// AutoCompleteMode enumeration values.
+ ///
+ private static class AutoCompleteSelection
+ {
+ ///
+ /// Index function that retrieves the selector for the provided
+ /// AutoCompleteMode.
+ ///
+ /// The built-in autocomplete mode.
+ /// Returns the string-based selector function.
+ public static AutoCompleteSelector GetSelector(AutoCompleteMode completeMode)
+ {
+ switch (completeMode)
+ {
+ case AutoCompleteMode.Replace:
+ return Replace;
+ case AutoCompleteMode.Append:
+ return Append;
+ case AutoCompleteMode.Custom:
+ default:
+ return null;
+ }
+ }
+
+ ///
+ /// Implements AutoCompleteMode.Replace.
+ ///
+ /// The AutoCompleteBox prefix text.
+ /// The item's string value.
+ ///
+ /// Return the and ignores the
+ /// .
+ ///
+ private static string Replace(string text, string value)
+ {
+ return value ?? String.Empty;
+ }
+
+ ///
+ /// Implements AutoCompleteMode.Append.
+ ///
+ /// The AutoCompleteBox prefix text.
+ /// The item's string value.
+ ///
+ /// Returns the concatenated string.
+ ///
+ private static string Append(string text, string value)
+ {
+ return text + value;
+ }
+ }
+
///
/// A framework element that permits a binding to be evaluated in a new data
/// context leaf node.