diff --git a/src/Ursa/Controls/AutoCompleteBox/MultiAutoCompleteBox.Properties.cs b/src/Ursa/Controls/AutoCompleteBox/MultiAutoCompleteBox.Properties.cs
index f302bae..5e1b325 100644
--- a/src/Ursa/Controls/AutoCompleteBox/MultiAutoCompleteBox.Properties.cs
+++ b/src/Ursa/Controls/AutoCompleteBox/MultiAutoCompleteBox.Properties.cs
@@ -1,11 +1,6 @@
-using System;
using System.Collections;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Threading;
-using System.Threading.Tasks;
using Avalonia;
-using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Controls;
using Avalonia.Data;
@@ -32,8 +27,7 @@ public partial class MultiAutoCompleteBox
/// The identifier for the property.
public static readonly StyledProperty MinimumPrefixLengthProperty =
AvaloniaProperty.Register(
- nameof(MinimumPrefixLength), 0,
- validate: IsValidMinimumPrefixLength);
+ nameof(MinimumPrefixLength), validate: IsValidMinimumPrefixLength);
///
/// Identifies the property.
diff --git a/src/Ursa/Controls/AutoCompleteBox/MultiAutoCompleteBox.cs b/src/Ursa/Controls/AutoCompleteBox/MultiAutoCompleteBox.cs
index 47d1d0b..604a4db 100644
--- a/src/Ursa/Controls/AutoCompleteBox/MultiAutoCompleteBox.cs
+++ b/src/Ursa/Controls/AutoCompleteBox/MultiAutoCompleteBox.cs
@@ -1,3 +1,7 @@
+// (c) Copyright Microsoft Corporation and Avalonia OÜ
+// This source is subject to the Microsoft Public License (Ms-PL) and MIT License.
+// All other rights reserved.
+
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
@@ -16,10 +20,8 @@ using Avalonia.Threading;
using Avalonia.VisualTree;
using Irihi.Avalonia.Shared.Contracts;
using Irihi.Avalonia.Shared.Helpers;
-using Irihi.Avalonia.Shared.Reactive;
using Ursa.Common;
-
namespace Ursa.Controls;
public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentControl
@@ -139,12 +141,6 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
private string? _searchText = string.Empty;
private bool _settingItemTemplateFromValueMemberBinding;
- ///
- /// Gets or sets a value indicating whether to skip the text update
- /// processing when the selected item is updated.
- ///
- private bool _skipSelectedItemTextUpdate;
-
///
/// The TextBox template part.
///
@@ -171,7 +167,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
///
/// Gets or sets the observable collection that contains references to
- /// all of the items in the generated view of data that is provided to
+ /// all the items in the generated view of data that is provided to
/// the selection-style control adapter.
///
private AvaloniaList? _view;
@@ -205,7 +201,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
}
///
- /// Gets or sets the drop down popup control.
+ /// Gets or sets the dropdown popup control.
///
private Popup? DropDownPopup { get; set; }
@@ -415,30 +411,6 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
UpdatePseudoClasses();
}
- private void OnSelectedItemPropertyChanged(AvaloniaPropertyChangedEventArgs e)
- {
- if (_ignorePropertyChange)
- {
- _ignorePropertyChange = false;
- return;
- }
-
- // Update the text display
- if (_skipSelectedItemTextUpdate)
- _skipSelectedItemTextUpdate = false;
- else
- OnSelectedItemChanged(e.NewValue);
-
- // Fire the SelectionChanged event
- var removed = new List();
- if (e.OldValue != null) removed.Add(e.OldValue);
-
- var added = new List();
- if (e.NewValue != null) added.Add(e.NewValue);
-
- OnSelectionChanged(new SelectionChangedEventArgs(SelectionChangedEvent, removed, added));
- }
-
///
/// TextProperty property changed handler.
///
@@ -508,7 +480,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
OnItemsSourceChanged((IEnumerable?)e.NewValue);
}
- private void OnItemTemplatePropertyChanged(AvaloniaPropertyChangedEventArgs e)
+ private void OnItemTemplatePropertyChanged(AvaloniaPropertyChangedEventArgs _)
{
if (!_settingItemTemplateFromValueMemberBinding)
_itemTemplateIsFromValueMemberBinding = false;
@@ -521,7 +493,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
var template =
new FuncDataTemplate(
typeof(object),
- (o, _) =>
+ (_, _) =>
{
var control = new ContentControl();
if (value is not null)
@@ -583,9 +555,9 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
SelectionAdapter = GetSelectionAdapterPart(e.NameScope);
TextBox = e.NameScope.Find(ElementTextBox);
- // If the drop down property indicates that the popup is open,
+ // If the dropdown property indicates that the popup is open,
// flip its value to invoke the changed handler.
- if (IsDropDownOpen && DropDownPopup != null && !DropDownPopup.IsOpen) OpeningDropDown(false);
+ if (IsDropDownOpen && DropDownPopup is { IsOpen: false }) OpeningDropDown(false);
base.OnApplyTemplate(e);
_selectedItemsControl = e.NameScope.Find(PART_SelectedItemsControl);
@@ -634,10 +606,10 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
if (e.Handled || !IsEnabled) return;
- // The drop down is open, pass along the key event arguments to the
+ // The dropdown is open, pass along the key event arguments to the
// selection adapter. If it isn't handled by the adapter's logic,
// then we handle some simple navigation scenarios for controlling
- // the drop down.
+ // the dropdown.
if (IsDropDownOpen)
{
if (SelectionAdapter != null)
@@ -654,7 +626,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
}
else
{
- // The drop down is not open, the Down key will toggle it open.
+ // The dropdown is not open, the Down key will toggle it open.
// Ignore key buttons, if they are used for XY focus.
if (e.Key == Key.Down
&& !this.IsAllowedXYNavigationMode(e.KeyDeviceType))
@@ -755,9 +727,10 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
else
{
// Check if we still have focus in the parent's focus scope
- if (GetFocusScope() is { } scope &&
+ // Add a special check for ListBoxItem because it should be closed when focus switch to dropdown.
+ if (GetFocusScope() is not null &&
(TopLevel.GetTopLevel(this)?.FocusManager?.GetFocusedElement() is not { } focused ||
- (focused != this && focused is not ListBoxItem && focused is Visual v && !this.IsVisualAncestorOf(v))))
+ (!Equals(focused, this) && focused is not ListBoxItem && focused is Visual v && !this.IsVisualAncestorOf(v))))
SetCurrentValue(IsDropDownOpenProperty, false);
_userCalledPopulate = false;
@@ -998,7 +971,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
}
///
- /// Begin opening the drop down by firing cancelable events, opening the
+ /// Begin opening the dropdown by firing cancelable events, opening the
/// drop-down or reverting, depending on the event argument values.
///
/// The original value, if needed for a revert.
@@ -1029,7 +1002,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
/// The event data.
private void DropDownPopup_Closed(object? sender, System.EventArgs e)
{
- // Force the drop down dependency property to be false.
+ // Force the dropdown dependency property to be false.
if (IsDropDownOpen) SetCurrentValue(IsDropDownOpenProperty, false);
// Fire the DropDownClosed event
@@ -1161,7 +1134,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
///
protected virtual string? FormatValue(object? value)
{
- if (_valueBindingEvaluator != null) return _valueBindingEvaluator.GetDynamicValue(value) ?? string.Empty;
+ if (_valueBindingEvaluator != null) return _valueBindingEvaluator.GetDynamicValue(value);
return value == null ? string.Empty : value.ToString();
}
@@ -1249,7 +1222,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
return;
}
- if (newText == null) newText = string.Empty;
+ newText ??= string.Empty;
// The TextBox.TextChanged event was not firing immediately and
// was causing an immediate update, even with wrapping. If there is
@@ -1334,7 +1307,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
// cache properties
var textFilter = TextFilter;
var itemFilter = ItemFilter;
- var _newViewItems = new Collection();
+ var newViewItems = new Collection();
// if the mode is objectFiltering and itemFilter is null, we throw an exception
if (objectFiltering && itemFilter is null)
@@ -1355,11 +1328,11 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
else if (objectFiltering) inResults = itemFilter!(text, item);
}
- if (inResults) _newViewItems.Add(item);
+ if (inResults) newViewItems.Add(item);
}
_view?.Clear();
- _view?.AddRange(_newViewItems);
+ _view?.AddRange(newViewItems);
// Clear the evaluator to discard a reference to the last item
_valueBindingEvaluator?.ClearDataContext();
@@ -1393,7 +1366,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
// Clear and set the view on the selection adapter
ClearView();
- if (SelectionAdapter != null && SelectionAdapter.ItemsSource != _view) SelectionAdapter.ItemsSource = _view;
+ if (SelectionAdapter != null && !Equals(SelectionAdapter.ItemsSource, _view)) SelectionAdapter.ItemsSource = _view;
if (IsDropDownOpen) RefreshView();
}
@@ -1461,7 +1434,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
PopulatedEventArgs populated = new PopulatedEventArgs(new ReadOnlyCollection(_view!));
OnPopulated(populated);
- if (SelectionAdapter != null && SelectionAdapter.ItemsSource != _view) SelectionAdapter.ItemsSource = _view;
+ if (SelectionAdapter != null && !Equals(SelectionAdapter.ItemsSource, _view)) SelectionAdapter.ItemsSource = _view;
var isDropDownOpen = _userCalledPopulate && _view!.Count > 0;
if (isDropDownOpen != IsDropDownOpen)
@@ -1489,8 +1462,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
///
private void UpdateTextCompletion(bool userInitiated)
{
- // By default this method will clear the selected value
- object? newSelectedItem = null;
+ // By default, this method will clear the selected value
var text = Text;
// Text search is StartsWith explicit and only when enabled, in
@@ -1510,7 +1482,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
// first item in the view is used. This will improve
// performance on the lookup. It assumes that the
// FilterMode the user has selected is an acceptable
- // case sensitive matching function for their scenario.
+ // case-sensitive matching function for their scenario.
var top = FilterMode == AutoCompleteFilterMode.StartsWith ||
FilterMode == AutoCompleteFilterMode.StartsWithCaseSensitive
? _view[0]
@@ -1519,7 +1491,6 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
// If the search was successful, update SelectedItem
if (top != null)
{
- newSelectedItem = top;
var topString = FormatValue(top, true);
// Only replace partially when the two words being the same
@@ -1537,28 +1508,8 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
}
}
}
- else
- {
- // Perform an exact string lookup for the text. This is a
- // design change from the original Toolkit release when the
- // IsTextCompletionEnabled property behaved just like the
- // WPF ComboBox's IsTextSearchEnabled property.
- //
- // This change provides the behavior that most people expect
- // to find: a lookup for the value is always performed.
- newSelectedItem = TryGetMatch(text, _view,
- AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.EqualsCaseSensitive));
- }
}
- // Update the selected item property
-
- // TODO set selection.
- /*
- if (SelectedItem != newSelectedItem) _skipSelectedItemTextUpdate = true;
- SetCurrentValue(SelectedItemProperty, newSelectedItem);
- */
-
// Restore updates for TextSelection
if (_ignoreTextSelectionChange)
{
@@ -1584,7 +1535,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
if (predicate is null)
return null;
- if (view != null && view.Count > 0)
+ if (view?.Count > 0)
foreach (object o in view)
if (predicate(searchText, FormatValue(o)))
return o;
@@ -1607,31 +1558,6 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
}
}
- ///
- /// Called when the selected item is changed, updates the text value
- /// that is displayed in the text box part.
- ///
- /// The new item.
- private void OnSelectedItemChanged(object? newItem)
- {
- string? text;
-
- if (newItem == null)
- text = SearchText;
- else if (TextSelector != null)
- text = TextSelector(SearchText, FormatValue(newItem, true));
- else if (ItemSelector != null)
- text = ItemSelector(SearchText, newItem);
- else
- text = FormatValue(newItem, true);
-
- // Update the Text property and the TextBox values
- UpdateTextValue(text);
-
- // Move the caret to the end of the text box
- ClearTextBoxSelection();
- }
-
///
/// Handles the SelectionChanged event of the selection adapter.
///
@@ -1759,7 +1685,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
/// The AutoCompleteBox prefix text.
/// The item's string value.
/// Returns true if the condition is met.
- public static bool StartsWith(string? text, string? value)
+ private static bool StartsWith(string? text, string? value)
{
if (value is not null && text is not null)
return value.StartsWith(text, StringComparison.CurrentCultureIgnoreCase);
@@ -1772,7 +1698,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
/// The AutoCompleteBox prefix text.
/// The item's string value.
/// Returns true if the condition is met.
- public static bool StartsWithCaseSensitive(string? text, string? value)
+ private static bool StartsWithCaseSensitive(string? text, string? value)
{
if (value is not null && text is not null)
return value.StartsWith(text, StringComparison.CurrentCulture);
@@ -1785,7 +1711,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
/// The AutoCompleteBox prefix text.
/// The item's string value.
/// Returns true if the condition is met.
- public static bool StartsWithOrdinal(string? text, string? value)
+ private static bool StartsWithOrdinal(string? text, string? value)
{
if (value is not null && text is not null)
return value.StartsWith(text, StringComparison.OrdinalIgnoreCase);
@@ -1798,7 +1724,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
/// The AutoCompleteBox prefix text.
/// The item's string value.
/// Returns true if the condition is met.
- public static bool StartsWithOrdinalCaseSensitive(string? text, string? value)
+ private static bool StartsWithOrdinalCaseSensitive(string? text, string? value)
{
if (value is not null && text is not null)
return value.StartsWith(text, StringComparison.Ordinal);
@@ -1807,12 +1733,12 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
///
/// Check if the prefix is contained in the string value. The current
- /// culture's case insensitive string comparison operator is used.
+ /// culture's case-insensitive string comparison operator is used.
///
/// The AutoCompleteBox prefix text.
/// The item's string value.
/// Returns true if the condition is met.
- public static bool Contains(string? text, string? value)
+ private static bool Contains(string? text, string? value)
{
return Contains(value, text, StringComparison.CurrentCultureIgnoreCase);
}
@@ -1823,7 +1749,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
/// The AutoCompleteBox prefix text.
/// The item's string value.
/// Returns true if the condition is met.
- public static bool ContainsCaseSensitive(string? text, string? value)
+ private static bool ContainsCaseSensitive(string? text, string? value)
{
return Contains(value, text, StringComparison.CurrentCulture);
}
@@ -1834,7 +1760,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
/// The AutoCompleteBox prefix text.
/// The item's string value.
/// Returns true if the condition is met.
- public static bool ContainsOrdinal(string? text, string? value)
+ private static bool ContainsOrdinal(string? text, string? value)
{
return Contains(value, text, StringComparison.OrdinalIgnoreCase);
}
@@ -1845,7 +1771,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
/// The AutoCompleteBox prefix text.
/// The item's string value.
/// Returns true if the condition is met.
- public static bool ContainsOrdinalCaseSensitive(string? text, string? value)
+ private static bool ContainsOrdinalCaseSensitive(string? text, string? value)
{
return Contains(value, text, StringComparison.Ordinal);
}
@@ -1867,7 +1793,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
/// The AutoCompleteBox prefix text.
/// The item's string value.
/// Returns true if the condition is met.
- public static bool EqualsCaseSensitive(string? text, string? value)
+ private static bool EqualsCaseSensitive(string? text, string? value)
{
return string.Equals(value, text, StringComparison.CurrentCulture);
}
@@ -1878,7 +1804,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
/// The AutoCompleteBox prefix text.
/// The item's string value.
/// Returns true if the condition is met.
- public static bool EqualsOrdinal(string? text, string? value)
+ private static bool EqualsOrdinal(string? text, string? value)
{
return string.Equals(value, text, StringComparison.OrdinalIgnoreCase);
}
@@ -1889,7 +1815,7 @@ public partial class MultiAutoCompleteBox : TemplatedControl, IInnerContentContr
/// The AutoCompleteBox prefix text.
/// The item's string value.
/// Returns true if the condition is met.
- public static bool EqualsOrdinalCaseSensitive(string? text, string? value)
+ private static bool EqualsOrdinalCaseSensitive(string? text, string? value)
{
return string.Equals(value, text, StringComparison.Ordinal);
}