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

Prevent AutoCompleteBox getting stuck in a state where it can't drop down. #17074

Merged
merged 2 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
103 changes: 52 additions & 51 deletions src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1403,74 +1403,75 @@ private void RefreshView()
// Indicate that filtering is ongoing
_filterInAction = true;

if (_items == null)
try
{
ClearView();
return;
}
if (_items == null)
{
ClearView();
return;
}

// Cache the current text value
string text = Text ?? string.Empty;
// Cache the current text value
string text = Text ?? string.Empty;

// Determine if any filtering mode is on
bool stringFiltering = TextFilter != null;
bool objectFiltering = FilterMode == AutoCompleteFilterMode.Custom && TextFilter == null;

List<object> items = _items;
// Determine if any filtering mode is on
bool stringFiltering = TextFilter != null;
bool objectFiltering = FilterMode == AutoCompleteFilterMode.Custom && TextFilter == null;

// cache properties
var textFilter = TextFilter;
var itemFilter = ItemFilter;
var _newViewItems = new Collection<object>();

// if the mode is objectFiltering and itemFilter is null, we throw an exception
if (objectFiltering && itemFilter is null)
{
// indicate that filtering is not ongoing anymore
_filterInAction = false;
_cancelRequested = false;

throw new Exception(
"ItemFilter property can not be null when FilterMode has value AutoCompleteFilterMode.Custom");
}
List<object> items = _items;

foreach (object item in items)
{
// Exit the fitter when requested if cancellation is requested
if (_cancelRequested)
// cache properties
var textFilter = TextFilter;
var itemFilter = ItemFilter;
var _newViewItems = new Collection<object>();

// if the mode is objectFiltering and itemFilter is null, we throw an exception
if (objectFiltering && itemFilter is null)
{
return;
throw new Exception(
"ItemFilter property can not be null when FilterMode has value AutoCompleteFilterMode.Custom");
}

bool inResults = !(stringFiltering || objectFiltering);

if (!inResults)
foreach (object item in items)
{
if (stringFiltering)
// Exit the fitter when requested if cancellation is requested
if (_cancelRequested)
{
inResults = textFilter!(text, FormatValue(item));
return;
}
else if (objectFiltering)

bool inResults = !(stringFiltering || objectFiltering);

if (!inResults)
{
inResults = itemFilter!(text, item);
if (stringFiltering)
{
inResults = textFilter!(text, FormatValue(item));
}
else if (objectFiltering)
{
inResults = itemFilter!(text, item);
}
}
}

if (inResults)
{
_newViewItems.Add(item);
if (inResults)
{
_newViewItems.Add(item);
}
}
}

_view?.Clear();
_view?.AddRange(_newViewItems);

// Clear the evaluator to discard a reference to the last item
_valueBindingEvaluator?.ClearDataContext();
_view?.Clear();
_view?.AddRange(_newViewItems);

// indicate that filtering is not ongoing anymore
_filterInAction = false;
_cancelRequested = false;
// Clear the evaluator to discard a reference to the last item
_valueBindingEvaluator?.ClearDataContext();
}
finally
{
// indicate that filtering is not ongoing anymore
_filterInAction = false;
_cancelRequested = false;
}
}

/// <summary>
Expand Down
25 changes: 25 additions & 0 deletions tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,31 @@ public void CaretIndex_Changes()
});
}

[Fact]
public void Attempting_To_Open_Without_Items_Does_Not_Prevent_Future_Opening_With_Items()
{
RunTest((control, textbox) =>
{
// Allow the drop down to open without anything entered.
control.MinimumPrefixLength = 0;

// Clear the items.
var source = control.ItemsSource;
control.ItemsSource = null;
control.IsDropDownOpen = true;

// DropDown was not actually opened because there are no items.
Assert.False(control.IsDropDownOpen);

// Set the items and try to open the drop down again.
control.ItemsSource = source;
control.IsDropDownOpen = true;

// DropDown can now be opened.
Assert.True(control.IsDropDownOpen);
});
}

/// <summary>
/// Retrieves a defined predicate filter through a new AutoCompleteBox
/// control instance.
Expand Down
Loading