Skip to content

Commit f2fc8d0

Browse files
authored
Move IBinding to BindingBase and tidy up some binding APIs (#19589)
* Update ncrunch config. * Tidy up reflection and multi-binding APIs: - Move `BindingBase` and `MultiBinding` into Avalonia.Base - `BindingBase` becomes a true base class for all bindings, and contains only the `Instance` method - Properties common between reflection and compiled bindings are moved into `StandardBindingBase` - `Binding` is moved to Avalonia.Base and renamed to `ReflectionBinding` - A compatibility shim for `Binding` remains in Avalonia.Markup - Remove `IBinding` and `IBinding2` - Remove `ITreeDataTemplate's usage of `InstancedBinding` - Remove `NativeMenuBarPresenter`s usage of `InstancedBinding` - Remove `InstancedBinding` as it is now unused This required an update to the DataGrid submodule: cell data validation has been temporarily removed as this used `InstancedBinding`. * `Instance()` => `CreateInstance()`. The use of "Instance" as a verb is quite unusual apparently ;) * Seal classes where appropriate. * Seal classes where appropriate. * Remove `StandardBindingBase`. Simply duplicate the members in reflection and compiled binding classes. * Delete deleted submodule directory. * Add missing attribute. Fixes compile error. * Fix reference to removed class. * Update suppressions.
1 parent abb1722 commit f2fc8d0

85 files changed

Lines changed: 1264 additions & 1304 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<ProjectConfiguration>
2+
<Settings>
3+
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
4+
</Settings>
5+
</ProjectConfiguration>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<ProjectConfiguration>
2+
<Settings>
3+
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
4+
</Settings>
5+
</ProjectConfiguration>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<ProjectConfiguration>
2+
<Settings>
3+
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
4+
</Settings>
5+
</ProjectConfiguration>

api/Avalonia.nupkg.xml

Lines changed: 506 additions & 2 deletions
Large diffs are not rendered by default.

src/Avalonia.Base/Animation/AnimatorKeyFrame.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public IDisposable BindSetter(IAnimationSetter setter, Animatable targetControl)
4646
Property = setter.Property;
4747
var value = setter.Value;
4848

49-
if (value is IBinding binding)
49+
if (value is BindingBase binding)
5050
{
5151
return Bind(ValueProperty, binding, targetControl);
5252
}

src/Avalonia.Base/AvaloniaObject.cs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public object? this[AvaloniaProperty property]
9898
/// Gets or sets a binding for a <see cref="AvaloniaProperty"/>.
9999
/// </summary>
100100
/// <param name="binding">The binding information.</param>
101-
public IBinding this[IndexerDescriptor binding]
101+
public BindingBase this[IndexerDescriptor binding]
102102
{
103103
get { return new IndexerBinding(this, binding.Property!, binding.Mode); }
104104
set { this.Bind(binding.Property!, value); }
@@ -417,14 +417,14 @@ public void SetCurrentValue<T>(StyledProperty<T> property, T value)
417417
}
418418

419419
/// <summary>
420-
/// Binds a <see cref="AvaloniaProperty"/> to an <see cref="IBinding"/>.
420+
/// Binds a <see cref="AvaloniaProperty"/> to an <see cref="BindingBase"/>.
421421
/// </summary>
422422
/// <param name="property">The property.</param>
423423
/// <param name="binding">The binding.</param>
424424
/// <returns>
425425
/// The binding expression which represents the binding instance on this object.
426426
/// </returns>
427-
public BindingExpressionBase Bind(AvaloniaProperty property, IBinding binding)
427+
public BindingExpressionBase Bind(AvaloniaProperty property, BindingBase binding)
428428
{
429429
return Bind(property, binding, null);
430430
}
@@ -474,9 +474,9 @@ public IDisposable Bind<T>(
474474
VerifyAccess();
475475
ValidatePriority(priority);
476476

477-
if (source is IBinding2 b)
477+
if (source is BindingBase b)
478478
{
479-
if (b.Instance(this, property, null) is not UntypedBindingExpressionBase expression)
479+
if (b.CreateInstance(this, property, null) is not UntypedBindingExpressionBase expression)
480480
throw new NotSupportedException($"Binding returned unsupported {nameof(BindingExpressionBase)}.");
481481

482482
if (priority != expression.Priority)
@@ -574,9 +574,9 @@ public IDisposable Bind<T>(
574574
throw new ArgumentException($"The property {property.Name} is readonly.");
575575
}
576576

577-
if (source is IBinding2 b)
577+
if (source is BindingBase b)
578578
{
579-
if (b.Instance(this, property, null) is not UntypedBindingExpressionBase expression)
579+
if (b.CreateInstance(this, property, null) is not UntypedBindingExpressionBase expression)
580580
throw new NotSupportedException($"Binding returned unsupported {nameof(BindingExpressionBase)}.");
581581
return GetValueStore().AddBinding(property, expression);
582582
}
@@ -643,7 +643,7 @@ public IDisposable Bind<T>(
643643
public void CoerceValue(AvaloniaProperty property) => _values.CoerceValue(property);
644644

645645
/// <summary>
646-
/// Binds a <see cref="AvaloniaProperty"/> to an <see cref="IBinding"/>.
646+
/// Binds a <see cref="AvaloniaProperty"/> to an <see cref="BindingBase"/>.
647647
/// </summary>
648648
/// <param name="property">The property.</param>
649649
/// <param name="binding">The binding.</param>
@@ -656,11 +656,9 @@ public IDisposable Bind<T>(
656656
/// <returns>
657657
/// The binding expression which represents the binding instance on this object.
658658
/// </returns>
659-
internal BindingExpressionBase Bind(AvaloniaProperty property, IBinding binding, object? anchor)
659+
internal BindingExpressionBase Bind(AvaloniaProperty property, BindingBase binding, object? anchor)
660660
{
661-
if (binding is not IBinding2 b)
662-
throw new NotSupportedException($"Unsupported IBinding implementation '{binding}'.");
663-
if (b.Instance(this, property, anchor) is not UntypedBindingExpressionBase expression)
661+
if (binding.CreateInstance(this, property, anchor) is not UntypedBindingExpressionBase expression)
664662
throw new NotSupportedException($"Binding returned unsupported {nameof(BindingExpressionBase)}.");
665663

666664
return GetValueStore().AddBinding(property, expression);

src/Avalonia.Base/AvaloniaObjectExtensions.cs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ namespace Avalonia
1111
public static class AvaloniaObjectExtensions
1212
{
1313
/// <summary>
14-
/// Converts an <see cref="IObservable{T}"/> to an <see cref="IBinding"/>.
14+
/// Converts an <see cref="IObservable{T}"/> to an <see cref="BindingBase"/>.
1515
/// </summary>
1616
/// <typeparam name="T">The type produced by the observable.</typeparam>
1717
/// <param name="source">The observable</param>
18-
/// <returns>An <see cref="IBinding"/>.</returns>
19-
public static IBinding ToBinding<T>(this IObservable<T> source)
18+
/// <returns>An <see cref="BindingBase"/>.</returns>
19+
public static BindingBase ToBinding<T>(this IObservable<T> source)
2020
{
2121
return new BindingAdaptor(
2222
typeof(T).IsValueType
@@ -228,7 +228,7 @@ public static IDisposable Bind<T>(
228228
}
229229

230230
/// <summary>
231-
/// Binds a property on an <see cref="AvaloniaObject"/> to an <see cref="IBinding"/>.
231+
/// Binds a property on an <see cref="AvaloniaObject"/> to an <see cref="BindingBase"/>.
232232
/// </summary>
233233
/// <param name="target">The object.</param>
234234
/// <param name="property">The property to bind.</param>
@@ -244,7 +244,7 @@ public static IDisposable Bind<T>(
244244
public static IDisposable Bind(
245245
this AvaloniaObject target,
246246
AvaloniaProperty property,
247-
IBinding binding,
247+
BindingBase binding,
248248
object? anchor = null)
249249
{
250250
target = target ?? throw new ArgumentNullException(nameof(target));
@@ -359,7 +359,7 @@ public static IDisposable AddClassHandler<TTarget, TValue>(
359359
return observable.Subscribe(new ClassHandlerObserver<TTarget, TValue>(action));
360360
}
361361

362-
private class BindingAdaptor : IBinding2
362+
private class BindingAdaptor : BindingBase
363363
{
364364
private readonly IObservable<object?> _source;
365365

@@ -368,17 +368,10 @@ public BindingAdaptor(IObservable<object?> source)
368368
this._source = source;
369369
}
370370

371-
public InstancedBinding? Initiate(
371+
internal override BindingExpressionBase CreateInstance(
372372
AvaloniaObject target,
373-
AvaloniaProperty? targetProperty,
374-
object? anchor = null,
375-
bool enableDataValidation = false)
376-
{
377-
var expression = new UntypedObservableBindingExpression(_source, BindingPriority.LocalValue);
378-
return new InstancedBinding(expression, BindingMode.OneWay, BindingPriority.LocalValue);
379-
}
380-
381-
BindingExpressionBase IBinding2.Instance(AvaloniaObject target, AvaloniaProperty? property, object? anchor)
373+
AvaloniaProperty? property,
374+
object? anchor)
382375
{
383376
return new UntypedObservableBindingExpression(_source, BindingPriority.LocalValue);
384377
}

src/Avalonia.Base/ClassBindingManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ internal static class ClassBindingManager
1212
private static readonly Dictionary<string, AvaloniaProperty> s_RegisteredProperties =
1313
new Dictionary<string, AvaloniaProperty>();
1414

15-
public static IDisposable Bind(StyledElement target, string className, IBinding source, object anchor)
15+
public static IDisposable Bind(StyledElement target, string className, BindingBase source, object anchor)
1616
{
1717
var prop = GetClassProperty(className);
1818
return target.Bind(prop, source);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
namespace Avalonia.Data;
2+
3+
/// <summary>
4+
/// Base class for the various types of binding supported by Avalonia.
5+
/// </summary>
6+
public abstract class BindingBase
7+
{
8+
/// <summary>
9+
/// Creates a <see cref="BindingExpressionBase"/> from a binding.
10+
/// </summary>
11+
/// <param name="target">The target of the binding.</param>
12+
/// <param name="targetProperty">The target property of the binding.</param>
13+
/// <param name="anchor">
14+
/// If <paramref name="target"/> is not a control, provides an anchor object from which to
15+
/// locate a data context or other controls.
16+
/// </param>
17+
/// <returns>
18+
/// A newly instantiated <see cref="BindingExpressionBase"/>.
19+
/// </returns>
20+
/// <remarks>
21+
/// This is a low-level method which returns a binding expression that is not yet connected to
22+
/// a binding sink, and so is inactive.
23+
/// </remarks>
24+
internal abstract BindingExpressionBase CreateInstance(
25+
AvaloniaObject target,
26+
AvaloniaProperty? targetProperty,
27+
object? anchor);
28+
}

src/Avalonia.Base/Data/BindingExpressionBase.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ private protected BindingExpressionBase()
1010
{
1111
}
1212

13-
internal BindingMode Mode { get; private protected set; }
14-
1513
public virtual void Dispose()
1614
{
1715
GC.SuppressFinalize(this);

0 commit comments

Comments
 (0)