Browse Source

Remove AutoCompleteBox.BindingEvaluator (#20596)

* Remove AutoCompleteBox.BindingEvaluator

* Fix AutoCompleteBoxPage sample

* Update API suppressions
pull/20108/merge
Julien Lebosquain 3 days ago
committed by GitHub
parent
commit
313bceea90
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 12
      api/Avalonia.nupkg.xml
  2. 20
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  3. 26
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.Properties.cs
  4. 153
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

12
api/Avalonia.nupkg.xml

@ -31,6 +31,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left> <Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right> <Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression> </Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.AutoCompleteBox.BindingEvaluator`1</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression> <Suppression>
<DiagnosticId>CP0001</DiagnosticId> <DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.NativeMenuItemToggleType</Target> <Target>T:Avalonia.Controls.NativeMenuItemToggleType</Target>
@ -79,6 +85,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left> <Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right> <Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression> </Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.AutoCompleteBox.BindingEvaluator`1</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression> <Suppression>
<DiagnosticId>CP0001</DiagnosticId> <DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Controls.NativeMenuItemToggleType</Target> <Target>T:Avalonia.Controls.NativeMenuItemToggleType</Target>

20
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs

@ -7,30 +7,12 @@ using Avalonia.Controls;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Data.Converters; using Avalonia.Data.Converters;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using ControlCatalog.Models;
namespace ControlCatalog.Pages namespace ControlCatalog.Pages
{ {
public partial class AutoCompleteBoxPage : UserControl public partial class AutoCompleteBoxPage : UserControl
{ {
public class StateData
{
public string Name { get; private set; }
public string Abbreviation { get; private set; }
public string Capital { get; private set; }
public StateData(string name, string abbreviatoin, string capital)
{
Name = name;
Abbreviation = abbreviatoin;
Capital = capital;
}
public override string ToString()
{
return Name;
}
}
private static StateData[] BuildAllStates() private static StateData[] BuildAllStates()
{ {
return new StateData[] return new StateData[]

26
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.Properties.cs

@ -191,6 +191,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty<object?> InnerRightContentProperty = public static readonly StyledProperty<object?> InnerRightContentProperty =
TextBox.InnerRightContentProperty.AddOwner<AutoCompleteBox>(); TextBox.InnerRightContentProperty.AddOwner<AutoCompleteBox>();
/// <summary>
/// Defines the <see cref="ValueMemberBinding" /> property.
/// </summary>
public static readonly StyledProperty<BindingBase?> ValueMemberBindingProperty =
AvaloniaProperty.Register<AutoCompleteBox, BindingBase?>(nameof(ValueMemberBinding));
/// <summary> /// <summary>
/// Gets or sets the caret index /// Gets or sets the caret index
/// </summary> /// </summary>
@ -311,26 +317,16 @@ namespace Avalonia.Controls
} }
/// <summary> /// <summary>
/// Gets or sets the <see cref="T:Avalonia.Data.Binding" /> that /// Gets or sets the <see cref="BindingBase" /> that is used to get the values for display in the text portion
/// is used to get the values for display in the text portion of /// of the <see cref="AutoCompleteBox" /> control.
/// the <see cref="AutoCompleteBox" />
/// control.
/// </summary> /// </summary>
/// <value>The <see cref="T:Avalonia.Data.IBinding" /> object used /// <value>The <see cref="T:Avalonia.Data.BindingBase" /> object used when binding to a collection property.</value>
/// when binding to a collection property.</value>
[AssignBinding] [AssignBinding]
[InheritDataTypeFromItems(nameof(ItemsSource))] [InheritDataTypeFromItems(nameof(ItemsSource))]
public BindingBase? ValueMemberBinding public BindingBase? ValueMemberBinding
{ {
get => _valueBindingEvaluator?.ValueBinding; get => GetValue(ValueMemberBindingProperty);
set set => SetValue(ValueMemberBindingProperty, value);
{
if (ValueMemberBinding != value)
{
_valueBindingEvaluator = new BindingEvaluator<string>(value);
OnValueMemberBindingChanged(value);
}
}
} }
/// <summary> /// <summary>

153
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

@ -189,7 +189,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// A control that can provide updated string values from a binding. /// A control that can provide updated string values from a binding.
/// </summary> /// </summary>
private BindingEvaluator<string>? _valueBindingEvaluator; private BindingEvaluator<string?>? _valueMemberBindingEvaluator;
/// <summary> /// <summary>
/// A weak subscription for the collection changed event. /// A weak subscription for the collection changed event.
@ -439,6 +439,7 @@ namespace Avalonia.Controls
if (!_settingItemTemplateFromValueMemberBinding) if (!_settingItemTemplateFromValueMemberBinding)
_itemTemplateIsFromValueMemberBinding = false; _itemTemplateIsFromValueMemberBinding = false;
} }
private void OnValueMemberBindingChanged(BindingBase? value) private void OnValueMemberBindingChanged(BindingBase? value)
{ {
if (_itemTemplateIsFromValueMemberBinding) if (_itemTemplateIsFromValueMemberBinding)
@ -460,6 +461,16 @@ namespace Avalonia.Controls
} }
} }
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ValueMemberBindingProperty)
{
OnValueMemberBindingChanged(change.GetNewValue<BindingBase?>());
}
}
static AutoCompleteBox() static AutoCompleteBox()
{ {
FocusableProperty.OverrideDefaultValue<AutoCompleteBox>(true); FocusableProperty.OverrideDefaultValue<AutoCompleteBox>(true);
@ -1181,25 +1192,6 @@ namespace Avalonia.Controls
} }
} }
/// <summary>
/// Formats an Item for text comparisons based on Converter
/// and ConverterCulture properties.
/// </summary>
/// <param name="value">The object to format.</param>
/// <param name="clearDataContext">A value indicating whether to clear
/// the data context after the lookup is performed.</param>
/// <returns>Formatted Value.</returns>
private string? FormatValue(object? value, bool clearDataContext)
{
string? result = FormatValue(value);
if (clearDataContext && _valueBindingEvaluator != null)
{
_valueBindingEvaluator.ClearDataContext();
}
return result;
}
/// <summary> /// <summary>
/// Converts the specified object to a string by using the /// Converts the specified object to a string by using the
/// <see cref="P:Avalonia.Data.Binding.Converter" /> and /// <see cref="P:Avalonia.Data.Binding.Converter" /> and
@ -1215,9 +1207,13 @@ namespace Avalonia.Controls
/// </remarks> /// </remarks>
protected virtual string? FormatValue(object? value) protected virtual string? FormatValue(object? value)
{ {
if (_valueBindingEvaluator != null) if (ValueMemberBinding is { } valueMemberBinding)
{ {
return _valueBindingEvaluator.GetDynamicValue(value) ?? String.Empty; _valueMemberBindingEvaluator ??= new();
_valueMemberBindingEvaluator.UpdateBinding(valueMemberBinding);
var result = _valueMemberBindingEvaluator.Evaluate(value) ?? string.Empty;
_valueMemberBindingEvaluator.ClearDataContext();
return result;
} }
return value == null ? String.Empty : value.ToString(); return value == null ? String.Empty : value.ToString();
@ -1451,9 +1447,6 @@ namespace Avalonia.Controls
_view?.Clear(); _view?.Clear();
_view?.AddRange(_newViewItems); _view?.AddRange(_newViewItems);
// Clear the evaluator to discard a reference to the last item
_valueBindingEvaluator?.ClearDataContext();
} }
finally finally
{ {
@ -1638,7 +1631,7 @@ namespace Avalonia.Controls
if (top != null) if (top != null)
{ {
newSelectedItem = top; newSelectedItem = top;
string? topString = FormatValue(top, true); string? topString = FormatValue(top);
// Only replace partially when the two words being the same // Only replace partially when the two words being the same
int minLength = Math.Min(topString?.Length ?? 0, Text?.Length ?? 0); int minLength = Math.Min(topString?.Length ?? 0, Text?.Length ?? 0);
@ -1744,7 +1737,7 @@ namespace Avalonia.Controls
} }
else if (TextSelector != null) else if (TextSelector != null)
{ {
text = TextSelector(SearchText, FormatValue(newItem, true)); text = TextSelector(SearchText, FormatValue(newItem));
} }
else if (ItemSelector != null) else if (ItemSelector != null)
{ {
@ -1752,7 +1745,7 @@ namespace Avalonia.Controls
} }
else else
{ {
text = FormatValue(newItem, true); text = FormatValue(newItem);
} }
// Update the Text property and the TextBox values // Update the Text property and the TextBox values
@ -2020,109 +2013,5 @@ namespace Avalonia.Controls
return string.Equals(value, text, StringComparison.Ordinal); return string.Equals(value, text, StringComparison.Ordinal);
} }
} }
// TODO12: Remove, this shouldn't be part of the public API. Use our internal BindingEvaluator instead.
/// <summary>
/// A framework element that permits a binding to be evaluated in a new data
/// context leaf node.
/// </summary>
/// <typeparam name="T">The type of dynamic binding to return.</typeparam>
public class BindingEvaluator<T> : Control
{
/// <summary>
/// Gets or sets the string value binding used by the control.
/// </summary>
private BindingBase? _binding;
/// <summary>
/// Identifies the Value dependency property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1002:AvaloniaProperty objects should not be owned by a generic type",
Justification = "This property is not supposed to be used from XAML.")]
public static readonly StyledProperty<T> ValueProperty =
AvaloniaProperty.Register<BindingEvaluator<T>, T>(nameof(Value));
/// <summary>
/// Gets or sets the data item value.
/// </summary>
public T Value
{
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
/// <summary>
/// Gets or sets the value binding.
/// </summary>
public BindingBase? ValueBinding
{
get => _binding;
set
{
_binding = value;
if (value is not null)
Bind(ValueProperty, value);
}
}
/// <summary>
/// Initializes a new instance of the BindingEvaluator class.
/// </summary>
public BindingEvaluator()
{ }
/// <summary>
/// Initializes a new instance of the BindingEvaluator class,
/// setting the initial binding to the provided parameter.
/// </summary>
/// <param name="binding">The initial string value binding.</param>
public BindingEvaluator(BindingBase? binding)
: this()
{
ValueBinding = binding;
}
/// <summary>
/// Clears the data context so that the control does not keep a
/// reference to the last-looked up item.
/// </summary>
public void ClearDataContext()
{
DataContext = null;
}
/// <summary>
/// Updates the data context of the framework element and returns the
/// updated binding value.
/// </summary>
/// <param name="o">The object to use as the data context.</param>
/// <param name="clearDataContext">If set to true, this parameter will
/// clear the data context immediately after retrieving the value.</param>
/// <returns>Returns the evaluated T value of the bound dependency
/// property.</returns>
public T GetDynamicValue(object o, bool clearDataContext)
{
DataContext = o;
T value = Value;
if (clearDataContext)
{
DataContext = null;
}
return value;
}
/// <summary>
/// Updates the data context of the framework element and returns the
/// updated binding value.
/// </summary>
/// <param name="o">The object to use as the data context.</param>
/// <returns>Returns the evaluated T value of the bound dependency
/// property.</returns>
public T GetDynamicValue(object? o)
{
DataContext = o;
return Value;
}
}
} }
} }

Loading…
Cancel
Save