-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Move IBinding
to BindingBase
and tidy up some binding APIs
#19589
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
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR consolidates Avalonia's binding architecture by introducing a new BindingBase
class and moving core binding components from Avalonia.Markup
to Avalonia.Base
. The primary goal is to simplify the binding API by removing the dual IBinding
/IBinding2
interface pattern and establishing a cleaner inheritance hierarchy.
Key changes include:
- Replacement of
IBinding
/IBinding2
interfaces with an abstractBindingBase
class containing an internalInstance
method - Introduction of
ReflectionBinding
as the new name for the previousBinding
class, withStandardBindingBase
containing common properties - Migration of binding-related code from
Avalonia.Markup
toAvalonia.Base
for better architectural organization
Reviewed Changes
Copilot reviewed 83 out of 84 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
src/Avalonia.Base/Data/BindingBase.cs | New abstract base class for all bindings with core Instance method |
src/Avalonia.Base/Data/ReflectionBinding.cs | New reflection-based binding implementation (renamed from Binding ) |
src/Avalonia.Base/Data/StandardBindingBase.cs | Common properties shared between reflection and compiled bindings |
src/Markup/Avalonia.Markup/Data/Binding.cs | Compatibility shim extending ReflectionBinding |
Multiple test files | Updates to use ReflectionBinding instead of Binding and BindingBase instead of IBinding |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
|
||
return true; | ||
} | ||
public BindingBase ProvideValue() => this; |
Copilot
AI
Sep 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The ProvideValue()
method should return TemplateBinding
instead of BindingBase
to maintain type safety and allow callers to access specific TemplateBinding
properties if needed.
public BindingBase ProvideValue() => this; | |
public TemplateBinding ProvideValue() => this; |
Copilot uses AI. Check for mistakes.
nativeItem.GetObservable(NativeMenuItem.HeaderProperty).ToBinding(), | ||
[!MenuItem.IconProperty] = nativeItem.GetObservable(NativeMenuItem.IconProperty) | ||
.Select(i => i is { } bitmap ? new Image { Source = bitmap } : null).ToBinding(), | ||
[!!MenuItem.IsCheckedProperty] = nativeItem[!!NativeMenuItem.IsCheckedProperty], |
Copilot
AI
Sep 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line uses a two-way binding syntax ([!!Property]
) but appears to be replacing the previous explicit two-way binding setup that was removed. Verify that this syntax provides the same two-way binding behavior as the removed InstancedBinding.TwoWay
call.
[!!MenuItem.IsCheckedProperty] = nativeItem[!!NativeMenuItem.IsCheckedProperty], | |
[!MenuItem.IsCheckedProperty] = new Binding | |
{ | |
Path = nameof(NativeMenuItem.IsChecked), | |
Source = nativeItem, | |
Mode = BindingMode.TwoWay | |
}, |
Copilot uses AI. Check for mistakes.
- 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`.
a23ade8
to
d3c0ff2
Compare
IDescription, | ||
ISetterValue, | ||
IDisposable | ||
public partial class TemplateBinding : BindingBase |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TemplateBinding
can no longer be both a binding and a binding expression now as we can't have multiple base classes. This will lead to increased memory usage: need to measure how much.
API diff between 12.0.999-cibuild0058697-alpha and 12.0.999Avalonia.Base (net6.0, net8.0, netstandard2.0) namespace Avalonia
{
public class AvaloniaObject
{
- public Avalonia.Data.BindingExpressionBase Bind(Avalonia.AvaloniaProperty property, Avalonia.Data.IBinding binding);
- public Avalonia.Data.IBinding this[Avalonia.Data.IndexerDescriptor binding] {
+ public Avalonia.Data.BindingBase this[Avalonia.Data.IndexerDescriptor binding] {
+ public Avalonia.Data.BindingExpressionBase Bind(Avalonia.AvaloniaProperty property, Avalonia.Data.BindingBase binding);
}
public static class AvaloniaObjectExtensions
{
- public static System.IDisposable Bind(this Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty property, Avalonia.Data.IBinding binding, object? anchor = null);
- public static Avalonia.Data.IBinding ToBinding<T>(this System.IObservable<T> source);
+ public static Avalonia.Data.BindingBase ToBinding<T>(this System.IObservable<T> source);
+ public static System.IDisposable Bind(this Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty property, Avalonia.Data.BindingBase binding, object? anchor = null);
}
public static class StyledElementExtensions
{
- public static System.IDisposable BindClass(this Avalonia.StyledElement target, string className, Avalonia.Data.IBinding source, object anchor);
+ public static System.IDisposable BindClass(this Avalonia.StyledElement target, string className, Avalonia.Data.BindingBase source, object anchor);
}
}
namespace Avalonia.Data
{
public static class BindingOperations
{
- public static System.IDisposable Apply(Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty property, Avalonia.Data.InstancedBinding binding, object? anchor);
- public static System.IDisposable Apply(Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty property, Avalonia.Data.InstancedBinding binding);
}
- public interface IBinding
- {
- Avalonia.Data.InstancedBinding? Initiate(Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty? targetProperty, object? anchor = null, bool? enableDataValidation = false);
- }
- public sealed class InstancedBinding
- {
- public static Avalonia.Data.InstancedBinding OneTime(System.IObservable<object?> observable, Avalonia.Data.BindingPriority priority = 0);
- public static Avalonia.Data.InstancedBinding OneTime(object value, Avalonia.Data.BindingPriority priority = 0);
- public static Avalonia.Data.InstancedBinding OneWay(System.IObservable<object?> observable, Avalonia.Data.BindingPriority priority = 0);
- public static Avalonia.Data.InstancedBinding OneWayToSource(System.IObserver<object?> observer, Avalonia.Data.BindingPriority priority = 0);
- public static Avalonia.Data.InstancedBinding TwoWay(System.IObservable<object?> observable, System.IObserver<object?> observer, Avalonia.Data.BindingPriority priority = 0);
- public Avalonia.Data.InstancedBinding WithPriority(Avalonia.Data.BindingPriority priority);
- public Avalonia.Data.BindingMode Mode { get; }
- public System.IObservable<object?> Observable { get; }
- public Avalonia.Data.BindingPriority Priority { get; }
- public System.IObservable<object?> Source { get; }
- }
public class TemplateBinding : Avalonia.Data.BindingBase
{
- public TemplateBinding() : base(default(Avalonia.Data.BindingPriority?), default(Avalonia.AvaloniaProperty?), default(bool?));
+ public TemplateBinding();
- public TemplateBinding(Avalonia.AvaloniaProperty property) : base(default(Avalonia.Data.BindingPriority?), default(Avalonia.AvaloniaProperty?), default(bool?));
+ public TemplateBinding(Avalonia.AvaloniaProperty property);
- public Avalonia.Data.InstancedBinding? Initiate(Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty? targetProperty, object? anchor = null, bool? enableDataValidation = false);
- public Avalonia.Data.IBinding ProvideValue();
+ public Avalonia.Data.BindingBase ProvideValue();
- protected override void StartCore();
- protected override void StopCore();
- public System.IDisposable Subscribe(System.IObserver<object?> observer);
- public override string Description { get; }
}
+ public abstract class BindingBase
+ {
+ protected BindingBase();
+ }
+ public class MultiBinding : Avalonia.Data.BindingBase
+ {
+ public MultiBinding();
+ public System.Collections.Generic.IList<Avalonia.Data.BindingBase> Bindings { get; set; }
+ public Avalonia.Data.Converters.IMultiValueConverter? Converter { get; set; }
+ public System.Globalization.CultureInfo? ConverterCulture { get; set; }
+ public object? ConverterParameter { get; set; }
+ public object FallbackValue { get; set; }
+ public Avalonia.Data.BindingMode? Mode { get; set; }
+ public Avalonia.Data.BindingPriority? Priority { get; set; }
+ public Avalonia.Data.RelativeSource? RelativeSource { get; set; }
+ public string? StringFormat { get; set; }
+ public object TargetNullValue { get; set; }
+ }
+ public class ReflectionBinding : Avalonia.Data.StandardBindingBase
+ {
+ public ReflectionBinding();
+ public ReflectionBinding(string path, Avalonia.Data.BindingMode mode);
+ public ReflectionBinding(string path);
+ public string? ElementName { get; set; }
+ public string Path { get; set; }
+ public Avalonia.Data.RelativeSource? RelativeSource { get; set; }
+ public object? Source { get; set; }
+ public System.Func<string?, string, System.Type>? TypeResolver { get; set; }
+ }
+ public class RelativeSource
+ {
+ public RelativeSource();
+ public RelativeSource(Avalonia.Data.RelativeSourceMode? mode);
+ public int? AncestorLevel { get; set; }
+ public System.Type? AncestorType { get; set; }
+ public Avalonia.Data.RelativeSourceMode? Mode { get; set; }
+ public Avalonia.Data.TreeType? Tree { get; set; }
+ }
+ public sealed class RelativeSourceMode
+ {
+ public const Avalonia.Data.RelativeSourceMode DataContext = 0;
+ public const Avalonia.Data.RelativeSourceMode FindAncestor = 3;
+ public const Avalonia.Data.RelativeSourceMode Self = 2;
+ public const Avalonia.Data.RelativeSourceMode TemplatedParent = 1;
+ public int value__;
+ }
+ public abstract class StandardBindingBase : Avalonia.Data.BindingBase
+ {
+ protected StandardBindingBase();
+ public Avalonia.Data.Converters.IValueConverter? Converter { get; set; }
+ public System.Globalization.CultureInfo? ConverterCulture { get; set; }
+ public object? ConverterParameter { get; set; }
+ public int? Delay { get; set; }
+ public object? FallbackValue { get; set; }
+ public Avalonia.Data.BindingMode? Mode { get; set; }
+ public Avalonia.Data.BindingPriority? Priority { get; set; }
+ public string? StringFormat { get; set; }
+ public object? TargetNullValue { get; set; }
+ public Avalonia.Data.UpdateSourceTrigger? UpdateSourceTrigger { get; set; }
+ }
+ public sealed class TreeType
+ {
+ public const Avalonia.Data.TreeType Logical = 1;
+ public int value__;
+ public const Avalonia.Data.TreeType Visual = 0;
+ }
} Avalonia.Controls (net6.0, net8.0, netstandard2.0) namespace Avalonia.Controls
{
public class AutoCompleteBox : Avalonia.Controls.Primitives.TemplatedControl
{
- public Avalonia.Data.IBinding? ValueMemberBinding { get; set; }
+ public Avalonia.Data.BindingBase? ValueMemberBinding { get; set; }
public class BindingEvaluator<T> : Avalonia.Controls.Control
{
- public BindingEvaluator(Avalonia.Data.IBinding? binding);
- public Avalonia.Data.IBinding? ValueBinding { get; set; }
+ public Avalonia.Data.BindingBase? ValueBinding { get; set; }
+ public BindingEvaluator(Avalonia.Data.BindingBase? binding);
}
}
public class ItemsControl : Avalonia.Controls.Primitives.TemplatedControl, Avalonia.LogicalTree.IChildIndexProvider
{
- public static readonly Avalonia.StyledProperty<Avalonia.Data.IBinding?> DisplayMemberBindingProperty;
+ public static readonly Avalonia.StyledProperty<Avalonia.Data.BindingBase?> DisplayMemberBindingProperty;
- public Avalonia.Data.IBinding? DisplayMemberBinding { get; set; }
+ public Avalonia.Data.BindingBase? DisplayMemberBinding { get; set; }
}
}
namespace Avalonia.Controls.Primitives
{
public class SelectingItemsControl : Avalonia.Controls.ItemsControl
{
- public static readonly Avalonia.StyledProperty<Avalonia.Data.IBinding?> SelectedValueBindingProperty;
+ public static readonly Avalonia.StyledProperty<Avalonia.Data.BindingBase?> SelectedValueBindingProperty;
- public Avalonia.Data.IBinding? SelectedValueBinding { get; set; }
+ public Avalonia.Data.BindingBase? SelectedValueBinding { get; set; }
}
public static class TextSearch
{
- public static readonly Avalonia.AttachedProperty<Avalonia.Data.IBinding?> TextBindingProperty;
+ public static readonly Avalonia.AttachedProperty<Avalonia.Data.BindingBase?> TextBindingProperty;
- public static Avalonia.Data.IBinding? GetTextBinding(Avalonia.Interactivity.Interactive interactive);
+ public static Avalonia.Data.BindingBase? GetTextBinding(Avalonia.Interactivity.Interactive interactive);
- public static void SetTextBinding(Avalonia.Interactivity.Interactive interactive, Avalonia.Data.IBinding? value);
+ public static void SetTextBinding(Avalonia.Interactivity.Interactive interactive, Avalonia.Data.BindingBase? value);
}
}
namespace Avalonia.Controls.Templates
{
public class FuncTreeDataTemplate : Avalonia.Controls.Templates.FuncDataTemplate, Avalonia.Controls.Templates.ITreeDataTemplate, Avalonia.Controls.Templates.IDataTemplate, Avalonia.Controls.Templates.ITemplate<object?, Avalonia.Controls.Control?>
{
- public Avalonia.Data.InstancedBinding ItemsSelector(object item);
+ public System.IDisposable BindChildren(Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty targetProperty, object item);
}
public interface ITreeDataTemplate : Avalonia.Controls.Templates.IDataTemplate, Avalonia.Controls.Templates.ITemplate<object?, Avalonia.Controls.Control?>
{
- Avalonia.Data.InstancedBinding? ItemsSelector(object item);
+ System.IDisposable BindChildren(Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty targetProperty, object item);
}
} Avalonia.Markup (net6.0, net8.0, netstandard2.0) namespace Avalonia.Data
{
public class Binding : Avalonia.Data.ReflectionBinding
{
- public Binding(string path, Avalonia.Data.BindingMode mode = 0);
+ public Binding(string path, Avalonia.Data.BindingMode mode);
- public override Avalonia.Data.InstancedBinding? Initiate(Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty? targetProperty, object? anchor = null, bool? enableDataValidation = false);
- public string? ElementName { get; set; }
- public string Path { get; set; }
- public Avalonia.Data.RelativeSource? RelativeSource { get; set; }
- public object? Source { get; set; }
- public System.Func<string?, string, System.Type>? TypeResolver { get; set; }
+ public Binding(string path);
}
- public abstract class BindingBase : Avalonia.Data.IBinding
- {
- public BindingBase();
- public BindingBase(Avalonia.Data.BindingMode? mode = 0);
- public abstract Avalonia.Data.InstancedBinding? Initiate(Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty? targetProperty, object? anchor = null, bool? enableDataValidation = false);
- public Avalonia.Data.Converters.IValueConverter? Converter { get; set; }
- public System.Globalization.CultureInfo? ConverterCulture { get; set; }
- public object? ConverterParameter { get; set; }
- public System.WeakReference? DefaultAnchor { get; set; }
- public int? Delay { get; set; }
- public object? FallbackValue { get; set; }
- public Avalonia.Data.BindingMode? Mode { get; set; }
- public System.WeakReference<Avalonia.Controls.INameScope?>? NameScope { get; set; }
- public Avalonia.Data.BindingPriority? Priority { get; set; }
- public string? StringFormat { get; set; }
- public object? TargetNullValue { get; set; }
- public Avalonia.Data.UpdateSourceTrigger? UpdateSourceTrigger { get; set; }
- }
- public class MultiBinding : Avalonia.Data.IBinding
- {
- public MultiBinding();
- public Avalonia.Data.InstancedBinding? Initiate(Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty? targetProperty, object? anchor = null, bool? enableDataValidation = false);
- public System.Collections.Generic.IList<Avalonia.Data.IBinding> Bindings { get; set; }
- public Avalonia.Data.Converters.IMultiValueConverter? Converter { get; set; }
- public System.Globalization.CultureInfo? ConverterCulture { get; set; }
- public object? ConverterParameter { get; set; }
- public object FallbackValue { get; set; }
- public Avalonia.Data.BindingMode? Mode { get; set; }
- public Avalonia.Data.BindingPriority? Priority { get; set; }
- public Avalonia.Data.RelativeSource? RelativeSource { get; set; }
- public string? StringFormat { get; set; }
- public object TargetNullValue { get; set; }
- }
- public class RelativeSource
- {
- public RelativeSource();
- public RelativeSource(Avalonia.Data.RelativeSourceMode? mode);
- public int? AncestorLevel { get; set; }
- public System.Type? AncestorType { get; set; }
- public Avalonia.Data.RelativeSourceMode? Mode { get; set; }
- public Avalonia.Data.TreeType? Tree { get; set; }
- }
- public sealed class RelativeSourceMode
- {
- public const Avalonia.Data.RelativeSourceMode DataContext = 0;
- public const Avalonia.Data.RelativeSourceMode FindAncestor = 3;
- public const Avalonia.Data.RelativeSourceMode Self = 2;
- public const Avalonia.Data.RelativeSourceMode TemplatedParent = 1;
- public int value__;
- }
- public sealed class TreeType
- {
- public const Avalonia.Data.TreeType Logical = 1;
- public int value__;
- public const Avalonia.Data.TreeType Visual = 0;
- }
} Avalonia.Markup.Xaml (net6.0, net8.0, netstandard2.0) namespace Avalonia.Markup.Xaml.MarkupExtensions
{
public class CompiledBindingExtension : Avalonia.Data.StandardBindingBase
{
- public override Avalonia.Data.InstancedBinding? Initiate(Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty? targetProperty, object? anchor = null, bool? enableDataValidation = false);
}
public class DynamicResourceExtension : Avalonia.Data.BindingBase
{
- public Avalonia.Data.IBinding ProvideValue(System.IServiceProvider serviceProvider);
+ public Avalonia.Data.BindingBase ProvideValue(System.IServiceProvider serviceProvider);
}
public class ReflectionBindingExtension : Avalonia.Data.ReflectionBinding
{
+ public Avalonia.Data.ReflectionBinding ProvideValue(System.IServiceProvider serviceProvider);
- public Avalonia.Data.Binding ProvideValue(System.IServiceProvider serviceProvider);
- public Avalonia.Data.Converters.IValueConverter? Converter { get; set; }
- public System.Globalization.CultureInfo? ConverterCulture { get; set; }
- public object? ConverterParameter { get; set; }
- public int? Delay { get; set; }
- public string? ElementName { get; set; }
- public object? FallbackValue { get; set; }
- public Avalonia.Data.BindingMode? Mode { get; set; }
- public string Path { get; set; }
- public Avalonia.Data.BindingPriority? Priority { get; set; }
- public Avalonia.Data.RelativeSource? RelativeSource { get; set; }
- public object? Source { get; set; }
- public string? StringFormat { get; set; }
- public object? TargetNullValue { get; set; }
- public Avalonia.Data.UpdateSourceTrigger? UpdateSourceTrigger { get; set; }
+ public ReflectionBindingExtension(string path, Avalonia.Data.BindingMode mode);
}
}
namespace Avalonia.Markup.Xaml.Templates
{
public class TreeDataTemplate : Avalonia.Controls.Templates.ITreeDataTemplate, Avalonia.Controls.Templates.IDataTemplate, Avalonia.Controls.Templates.ITemplate<object?, Avalonia.Controls.Control?>, Avalonia.Controls.Templates.ITypedDataTemplate
{
- public Avalonia.Data.InstancedBinding? ItemsSelector(object item);
+ public System.IDisposable BindChildren(Avalonia.AvaloniaObject target, Avalonia.AvaloniaProperty targetProperty, object item);
}
} |
I am not sure if I understand idea behind keeping it for compatibility with older apps, but it's really not ideal when // Avalonia.Base
// 1. Use "abstract Binding" instead of `StandardBindingBase`.
- public abstract class StandardBindingBase : BindingBase;
- public class Binding : ReflectionBinding
+ public abstract class Binding : BindingBase
// 2. Make ReflectionBinding internal and hidden (not a breaking change anyway)
-public class ReflectionBinding : StandardBindingBase;
+internal sealed class ReflectionBinding : Binding;
// 3. Add static methods to the Binding class:
public abstract class Binding : BindingBase
{
+ public static Binding Create(Func<>) - outside of this PR, but planned for future
+ [RequiresUnreferencedCode]
+ public static Binding Create(string) - returns ReflectionBinding
| // Avalonia.Markup.Xaml
// 4. Just adjusting extensions.
-public class ReflectionBindingExtension : ReflectionBinding;
+public class ReflectionBindingExtension : Binding; // ProvideValue returns internal ReflectionBinding
-public class CompiledBindingExtension : StandardBindingBase;
+public class CompiledBindingExtension : Binding; |
Another option, less breaking, (though, not sure how it can be implemented), would be following API: -public class Binding : ReflectionBinding
-public class ReflectionBinding;
+public class Binding : StandardBindingBase
{
+ [Obsolete("Use Binding Create(Func<>)")]
public Binding(string)
+ public static Binding Create(Func<>);
} Keeping |
What would you suggest? Moving all reflection features to e.g.
Yep, very good point - and one I went back and forth on. Originally I didn't want to include any compatibility APIs in this PR but the issue is we use I can definitely mark these constructors as |
If it's possible to build programs without reflection APIs being accessed at all (i.e. not being a base class for most common binding type) - then these reflection API can be in any assembly, we prefer. |
{ | ||
return InstancedBinding.OneTime(_itemsSelector(item)); | ||
target.SetCurrentValue(targetProperty, _itemsSelector(item)); | ||
return Disposable.Empty; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that correct? The documentation states that the returned IDisposable
can be disposed to remove the binding -- this isn't the case here.
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
Outdated
Show resolved
Hide resolved
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
Outdated
Show resolved
Hide resolved
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs
Outdated
Show resolved
Hide resolved
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs
Outdated
Show resolved
Hide resolved
The use of "Instance" as a verb is quite unusual apparently ;)
Simply duplicate the members in reflection and compiled binding classes.
What does the pull request do?
This is the first in a series of planned tidy-ups of our binding API.
This PR addresses a few problems that we have with our binding APIs:
IBinding
interface and internalIBinding2
interface containing the interface that is actually used. These interfaces need to be merged into an abstractBindingBase
class, with theInstance
method as an internal method onBindingBase
BindingBase
andBinding
are inAvalonia.Markup
instead ofAvalonia.Base
: this was because originally I assumed that we wouldn't need bindings outside of markup as we'd be using rx. This didn't turn out to be the case, andBinding
is very much a Base featureBindingBase
as it stands isn't really a base class for bindings:MultiBinding
doesn't inherit from it for example. Instead it holds common properties shared betweenBinding
andCompiledBindingExtension
InstancedBinding
has been marked as obsolete since 11.0 and should be removed for 12.0This PR makes the following changes to address these issues:
BindingBase
andMultiBinding
intoAvalonia.Base
BindingBase
becomes a true base class for all bindings, and contains only theInstance
methodProperties common between reflection and compiled bindings are moved intoit was decided that this was unnecessaryStandardBindingBase
Binding
is moved toAvalonia.Base
and renamed toReflectionBinding
Binding
remains in Avalonia.Markup - this allows the existing usages ofnew Binding("Path.Here")
to continue compilingIBinding
andIBinding2
ITreeDataTemplate's usage of
InstancedBinding`NativeMenuBarPresenter
s usage ofInstancedBinding
InstancedBinding
as it is now unusedBreaking changes
Lots. In particular
IBinding
->BindingBase
breaks a LOT of stuff.Also: This required an update to the DataGrid submodule: cell data validation has been temporarily removed as this used
InstancedBinding
.