diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj
index cd122a8b67..4a67191132 100644
--- a/src/Avalonia.Base/Avalonia.Base.csproj
+++ b/src/Avalonia.Base/Avalonia.Base.csproj
@@ -47,6 +47,9 @@
+
+
+
diff --git a/src/Avalonia.Base/Data/BindingOperations.cs b/src/Avalonia.Base/Data/BindingOperations.cs
index 0b737dd959..e53ae40cb1 100644
--- a/src/Avalonia.Base/Data/BindingOperations.cs
+++ b/src/Avalonia.Base/Data/BindingOperations.cs
@@ -41,54 +41,41 @@ namespace Avalonia.Data
{
case BindingMode.Default:
case BindingMode.OneWay:
- if (binding.Observable is null)
- throw new InvalidOperationException("InstancedBinding does not contain an observable.");
- return target.Bind(property, binding.Observable, binding.Priority);
+ return target.Bind(property, binding.Source, binding.Priority);
case BindingMode.TwoWay:
- if (binding.Observable is null)
- throw new InvalidOperationException("InstancedBinding does not contain an observable.");
- if (binding.Subject is null)
+ {
+ if (binding.Source is not IObserver observer)
throw new InvalidOperationException("InstancedBinding does not contain a subject.");
return new TwoWayBindingDisposable(
- target.Bind(property, binding.Observable, binding.Priority),
- target.GetObservable(property).Subscribe(binding.Subject));
+ target.Bind(property, binding.Source, binding.Priority),
+ target.GetObservable(property).Subscribe(observer));
+ }
case BindingMode.OneTime:
- if (binding.Observable is {} source)
- {
- // Perf: Avoid allocating closure in the outer scope.
- var targetCopy = target;
- var propertyCopy = property;
- var bindingCopy = binding;
-
- return source
- .Where(x => BindingNotification.ExtractValue(x) != AvaloniaProperty.UnsetValue)
- .Take(1)
- .Subscribe(x => targetCopy.SetValue(
- propertyCopy,
- BindingNotification.ExtractValue(x),
- bindingCopy.Priority));
- }
- else
- {
- target.SetValue(property, binding.Value, binding.Priority);
- return Disposable.Empty;
- }
+ {
+ // Perf: Avoid allocating closure in the outer scope.
+ var targetCopy = target;
+ var propertyCopy = property;
+ var bindingCopy = binding;
+
+ return binding.Source
+ .Where(x => BindingNotification.ExtractValue(x) != AvaloniaProperty.UnsetValue)
+ .Take(1)
+ .Subscribe(x => targetCopy.SetValue(
+ propertyCopy,
+ BindingNotification.ExtractValue(x),
+ bindingCopy.Priority));
+ }
case BindingMode.OneWayToSource:
{
- if (binding.Observable is null)
- throw new InvalidOperationException("InstancedBinding does not contain an observable.");
- if (binding.Subject is null)
+ if (binding.Source is not IObserver observer)
throw new InvalidOperationException("InstancedBinding does not contain a subject.");
- // Perf: Avoid allocating closure in the outer scope.
- var bindingCopy = binding;
-
return Observable.CombineLatest(
- binding.Observable,
+ binding.Source,
target.GetObservable(property),
(_, v) => v)
- .Subscribe(x => bindingCopy.Subject.OnNext(x));
+ .Subscribe(x => observer.OnNext(x));
}
default:
diff --git a/src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs b/src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs
index 536c14dcf9..92fc843394 100644
--- a/src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs
+++ b/src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs
@@ -3,7 +3,7 @@ using Avalonia.Reactive;
namespace Avalonia.Data.Core
{
- public class AvaloniaPropertyAccessorNode : SettableNode
+ internal class AvaloniaPropertyAccessorNode : SettableNode
{
private IDisposable? _subscription;
private readonly bool _enableValidation;
diff --git a/src/Avalonia.Base/Data/Core/BindingExpression.cs b/src/Avalonia.Base/Data/Core/BindingExpression.cs
index 55caf8070e..79942cb9ce 100644
--- a/src/Avalonia.Base/Data/Core/BindingExpression.cs
+++ b/src/Avalonia.Base/Data/Core/BindingExpression.cs
@@ -13,7 +13,7 @@ namespace Avalonia.Data.Core
/// that are sent and received.
///
[RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
- public class BindingExpression : LightweightObservableBase, IAvaloniaSubject, IDescription
+ internal class BindingExpression : LightweightObservableBase, IAvaloniaSubject, IDescription
{
private readonly ExpressionObserver _inner;
private readonly Type _targetType;
diff --git a/src/Avalonia.Base/Data/Core/EmptyExpressionNode.cs b/src/Avalonia.Base/Data/Core/EmptyExpressionNode.cs
index 4e142fbee9..b333fa9047 100644
--- a/src/Avalonia.Base/Data/Core/EmptyExpressionNode.cs
+++ b/src/Avalonia.Base/Data/Core/EmptyExpressionNode.cs
@@ -1,6 +1,6 @@
namespace Avalonia.Data.Core
{
- public class EmptyExpressionNode : ExpressionNode
+ internal class EmptyExpressionNode : ExpressionNode
{
public override string Description => ".";
}
diff --git a/src/Avalonia.Base/Data/Core/ExpressionNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNode.cs
index 5fb2bb5c13..30fc71cfb4 100644
--- a/src/Avalonia.Base/Data/Core/ExpressionNode.cs
+++ b/src/Avalonia.Base/Data/Core/ExpressionNode.cs
@@ -2,7 +2,7 @@ using System;
namespace Avalonia.Data.Core
{
- public abstract class ExpressionNode
+ internal abstract class ExpressionNode
{
protected static readonly WeakReference UnsetReference =
new WeakReference(AvaloniaProperty.UnsetValue);
diff --git a/src/Avalonia.Base/Data/Core/ExpressionObserver.cs b/src/Avalonia.Base/Data/Core/ExpressionObserver.cs
index 0818b5fa62..ce3549c4ad 100644
--- a/src/Avalonia.Base/Data/Core/ExpressionObserver.cs
+++ b/src/Avalonia.Base/Data/Core/ExpressionObserver.cs
@@ -11,7 +11,7 @@ namespace Avalonia.Data.Core
///
/// Observes and sets the value of an expression on an object.
///
- public class ExpressionObserver : LightweightObservableBase, IDescription
+ internal class ExpressionObserver : LightweightObservableBase, IDescription
{
///
/// An ordered collection of property accessor plugins that can be used to customize
diff --git a/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs b/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs
index 2fad96701d..9ec256225b 100644
--- a/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs
+++ b/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs
@@ -7,7 +7,7 @@ using Avalonia.Utilities;
namespace Avalonia.Data.Core
{
- public abstract class IndexerNodeBase : SettableNode,
+ internal abstract class IndexerNodeBase : SettableNode,
IWeakEventSubscriber,
IWeakEventSubscriber
{
diff --git a/src/Avalonia.Base/Data/Core/LogicalNotNode.cs b/src/Avalonia.Base/Data/Core/LogicalNotNode.cs
index 45837db73d..81b07bfe85 100644
--- a/src/Avalonia.Base/Data/Core/LogicalNotNode.cs
+++ b/src/Avalonia.Base/Data/Core/LogicalNotNode.cs
@@ -3,7 +3,7 @@ using System.Globalization;
namespace Avalonia.Data.Core
{
- public class LogicalNotNode : ExpressionNode, ITransformNode
+ internal class LogicalNotNode : ExpressionNode, ITransformNode
{
public override string Description => "!";
diff --git a/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs
index 34f8e568d4..f111d8917b 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs
@@ -8,7 +8,7 @@ namespace Avalonia.Data.Core.Plugins
///
/// Reads a property from a .
///
- public class AvaloniaPropertyAccessorPlugin : IPropertyAccessorPlugin
+ internal class AvaloniaPropertyAccessorPlugin : IPropertyAccessorPlugin
{
///
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
diff --git a/src/Avalonia.Base/Data/Core/Plugins/BindingPlugins.cs b/src/Avalonia.Base/Data/Core/Plugins/BindingPlugins.cs
new file mode 100644
index 0000000000..6d88d55774
--- /dev/null
+++ b/src/Avalonia.Base/Data/Core/Plugins/BindingPlugins.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+
+namespace Avalonia.Data.Core.Plugins
+{
+ ///
+ /// Holds a registry of plugins used for bindings.
+ ///
+ public static class BindingPlugins
+ {
+ ///
+ /// An ordered collection of property accessor plugins that can be used to customize
+ /// the reading and subscription of property values on a type.
+ ///
+ public static IList PropertyAccessors => ExpressionObserver.PropertyAccessors;
+
+ ///
+ /// An ordered collection of validation checker plugins that can be used to customize
+ /// the validation of view model and model data.
+ ///
+ public static IList DataValidators => ExpressionObserver.DataValidators;
+
+ ///
+ /// An ordered collection of stream plugins that can be used to customize the behavior
+ /// of the '^' stream binding operator.
+ ///
+ public static IList StreamHandlers => ExpressionObserver.StreamHandlers;
+ }
+}
diff --git a/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
index bc300386b9..ba5f59ea23 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
@@ -10,7 +10,7 @@ namespace Avalonia.Data.Core.Plugins
///
/// Validates properties on that have s.
///
- public class DataAnnotationsValidationPlugin : IDataValidationPlugin
+ internal class DataAnnotationsValidationPlugin : IDataValidationPlugin
{
///
[RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
diff --git a/src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs
index 2bb8da2c74..e60a341309 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/ExceptionValidationPlugin.cs
@@ -7,7 +7,7 @@ namespace Avalonia.Data.Core.Plugins
///
/// Validates properties that report errors by throwing exceptions.
///
- public class ExceptionValidationPlugin : IDataValidationPlugin
+ internal class ExceptionValidationPlugin : IDataValidationPlugin
{
///
[RequiresUnreferencedCode(TrimmingMessages.DataValidationPluginRequiresUnreferencedCodeMessage)]
diff --git a/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs
index 87a2f67ee8..3384a99333 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/IndeiValidationPlugin.cs
@@ -10,7 +10,7 @@ namespace Avalonia.Data.Core.Plugins
///
/// Validates properties on objects that implement .
///
- public class IndeiValidationPlugin : IDataValidationPlugin
+ internal class IndeiValidationPlugin : IDataValidationPlugin
{
private static readonly WeakEvent
ErrorsChangedWeakEvent = WeakEvent.Register(
diff --git a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
index 5b19e995cc..7c2caf02b4 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
@@ -11,7 +11,7 @@ namespace Avalonia.Data.Core.Plugins
/// Reads a property from a standard C# object that optionally supports the
/// interface.
///
- public class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin
+ internal class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin
{
private readonly Dictionary<(Type, string), PropertyInfo?> _propertyLookup =
new Dictionary<(Type, string), PropertyInfo?>();
diff --git a/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs
index 2397ce483d..8170edd653 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs
@@ -6,7 +6,7 @@ using System.Reflection;
namespace Avalonia.Data.Core.Plugins
{
- public class MethodAccessorPlugin : IPropertyAccessorPlugin
+ internal class MethodAccessorPlugin : IPropertyAccessorPlugin
{
private readonly Dictionary<(Type, string), MethodInfo?> _methodLookup =
new Dictionary<(Type, string), MethodInfo?>();
diff --git a/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs
index b40628fd35..2b9da0a61a 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs
@@ -10,7 +10,7 @@ namespace Avalonia.Data.Core.Plugins
/// Handles binding to s for the '^' stream binding operator.
///
[UnconditionalSuppressMessage("Trimming", "IL3050", Justification = TrimmingMessages.IgnoreNativeAotSupressWarningMessage)]
- public class ObservableStreamPlugin : IStreamPlugin
+ internal class ObservableStreamPlugin : IStreamPlugin
{
private static MethodInfo? s_observableGeneric;
private static MethodInfo? s_observableSelect;
diff --git a/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs
index 715f4604cf..42a050778e 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/TaskStreamPlugin.cs
@@ -10,7 +10,7 @@ namespace Avalonia.Data.Core.Plugins
/// Handles binding to s for the '^' stream binding operator.
///
[UnconditionalSuppressMessage("Trimming", "IL3050", Justification = TrimmingMessages.IgnoreNativeAotSupressWarningMessage)]
- public class TaskStreamPlugin : IStreamPlugin
+ internal class TaskStreamPlugin : IStreamPlugin
{
///
/// Checks whether this plugin handles the specified value.
diff --git a/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs b/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs
index 1b79fed6e7..3898d232ec 100644
--- a/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs
+++ b/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs
@@ -5,7 +5,7 @@ using Avalonia.Data.Core.Plugins;
namespace Avalonia.Data.Core
{
[RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)]
- public class PropertyAccessorNode : SettableNode
+ internal class PropertyAccessorNode : SettableNode
{
private readonly bool _enableValidation;
private IPropertyAccessorPlugin? _customPlugin;
diff --git a/src/Avalonia.Base/Data/Core/SettableNode.cs b/src/Avalonia.Base/Data/Core/SettableNode.cs
index 9ad9ace814..4980e4487a 100644
--- a/src/Avalonia.Base/Data/Core/SettableNode.cs
+++ b/src/Avalonia.Base/Data/Core/SettableNode.cs
@@ -2,7 +2,7 @@
namespace Avalonia.Data.Core
{
- public abstract class SettableNode : ExpressionNode
+ internal abstract class SettableNode : ExpressionNode
{
public bool SetTargetValue(object? value, BindingPriority priority)
{
diff --git a/src/Avalonia.Base/Data/Core/StreamNode.cs b/src/Avalonia.Base/Data/Core/StreamNode.cs
index ba18a2173b..d3da6414ac 100644
--- a/src/Avalonia.Base/Data/Core/StreamNode.cs
+++ b/src/Avalonia.Base/Data/Core/StreamNode.cs
@@ -6,7 +6,7 @@ using Avalonia.Reactive;
namespace Avalonia.Data.Core
{
[RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)]
- public class StreamNode : ExpressionNode
+ internal class StreamNode : ExpressionNode
{
private IStreamPlugin? _customPlugin = null;
private IDisposable? _subscription;
diff --git a/src/Avalonia.Base/Data/Core/TypeCastNode.cs b/src/Avalonia.Base/Data/Core/TypeCastNode.cs
index 3a2ca955fa..655bfbc7a1 100644
--- a/src/Avalonia.Base/Data/Core/TypeCastNode.cs
+++ b/src/Avalonia.Base/Data/Core/TypeCastNode.cs
@@ -4,7 +4,7 @@ using System.Text;
namespace Avalonia.Data.Core
{
- public class TypeCastNode : ExpressionNode
+ internal class TypeCastNode : ExpressionNode
{
public override string Description => $"as {TargetType.FullName}";
diff --git a/src/Avalonia.Base/Data/InstancedBinding.cs b/src/Avalonia.Base/Data/InstancedBinding.cs
index a60c1d72ec..00e5c3d8e6 100644
--- a/src/Avalonia.Base/Data/InstancedBinding.cs
+++ b/src/Avalonia.Base/Data/InstancedBinding.cs
@@ -1,5 +1,6 @@
using System;
using Avalonia.Reactive;
+using ObservableEx = Avalonia.Reactive.Observable;
namespace Avalonia.Data
{
@@ -14,11 +15,23 @@ namespace Avalonia.Data
///
public class InstancedBinding
{
- internal InstancedBinding(object? value, BindingMode mode, BindingPriority priority)
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The binding source.
+ /// The binding mode.
+ /// The priority of the binding.
+ ///
+ /// This constructor can be used to create any type of binding and as such requires an
+ /// as the binding source because this is the only binding
+ /// source which can be used for all binding modes. If you wish to create an instance with
+ /// something other than a subject, use one of the static creation methods on this class.
+ ///
+ internal InstancedBinding(IObservable source, BindingMode mode, BindingPriority priority)
{
Mode = mode;
Priority = priority;
- Value = value;
+ Source = source ?? throw new ArgumentNullException(nameof(source));
}
///
@@ -32,24 +45,12 @@ namespace Avalonia.Data
public BindingPriority Priority { get; }
///
- /// Gets the value or source of the binding.
- ///
- public object? Value { get; }
-
- ///
- /// Gets the as an observable.
+ /// Gets the binding source observable.
///
- public IObservable? Observable => Value as IObservable;
+ public IObservable Source { get; }
- ///
- /// Gets the as an observer.
- ///
- public IObserver? Observer => Value as IObserver;
-
- ///
- /// Gets the as an subject.
- ///
- internal IAvaloniaSubject? Subject => Value as IAvaloniaSubject;
+ [Obsolete("Use Source property")]
+ public IObservable Observable => Source;
///
/// Creates a new one-time binding with a fixed value.
@@ -61,7 +62,7 @@ namespace Avalonia.Data
object value,
BindingPriority priority = BindingPriority.LocalValue)
{
- return new InstancedBinding(value, BindingMode.OneTime, priority);
+ return new InstancedBinding(ObservableEx.SingleValue(value), BindingMode.OneTime, priority);
}
///
@@ -106,7 +107,7 @@ namespace Avalonia.Data
{
_ = observer ?? throw new ArgumentNullException(nameof(observer));
- return new InstancedBinding(observer, BindingMode.OneWayToSource, priority);
+ return new InstancedBinding((IObservable)observer, BindingMode.OneWayToSource, priority);
}
///
@@ -135,7 +136,7 @@ namespace Avalonia.Data
/// An instance.
public InstancedBinding WithPriority(BindingPriority priority)
{
- return new InstancedBinding(Value, Mode, priority);
+ return new InstancedBinding(Source, Mode, priority);
}
}
}
diff --git a/src/Avalonia.Base/Styling/Setter.cs b/src/Avalonia.Base/Styling/Setter.cs
index b7b44a7dfe..093597c6a0 100644
--- a/src/Avalonia.Base/Styling/Setter.cs
+++ b/src/Avalonia.Base/Styling/Setter.cs
@@ -109,7 +109,7 @@ namespace Avalonia.Styling
if (mode == BindingMode.OneWay || mode == BindingMode.TwoWay)
{
- return new PropertySetterBindingInstance(target, instance, Property, mode, i.Observable!);
+ return new PropertySetterBindingInstance(target, instance, Property, mode, i.Source);
}
throw new NotSupportedException();
diff --git a/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
index e859a6e725..8f532b9803 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
@@ -7,6 +7,7 @@ using Avalonia.Data;
using System;
using Avalonia.Controls.Utils;
using Avalonia.Markup.Xaml.MarkupExtensions;
+using Avalonia.Reactive;
namespace Avalonia.Controls
{
@@ -111,9 +112,9 @@ namespace Avalonia.Controls
if (result != null)
{
- if(result.Subject != null)
+ if(result.Source is IAvaloniaSubject subject)
{
- var bindingHelper = new CellEditBinding(result.Subject);
+ var bindingHelper = new CellEditBinding(subject);
var instanceBinding = new InstancedBinding(bindingHelper.InternalSubject, result.Mode, result.Priority);
BindingOperations.Apply(target, property, instanceBinding, null);
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
index 9990ad4731..d0a4de09ab 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
@@ -35,7 +35,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
};
}
- protected override ExpressionObserver CreateExpressionObserver(AvaloniaObject target, AvaloniaProperty targetProperty, object anchor, bool enableDataValidation)
+ private protected override ExpressionObserver CreateExpressionObserver(AvaloniaObject target, AvaloniaProperty targetProperty, object anchor, bool enableDataValidation)
{
if (Source != null)
{
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
index b7f2261324..2b62d33349 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
@@ -24,7 +24,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
}
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.CompiledBindingSafeSupressWarningMessage)]
- public ExpressionNode BuildExpression(bool enableValidation)
+ internal ExpressionNode BuildExpression(bool enableValidation)
{
ExpressionNode pathRoot = null;
ExpressionNode path = null;
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs
index 1252ec7eca..b543fd9c01 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs
@@ -3,7 +3,7 @@ using Avalonia.Data.Core;
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
- public class StrongTypeCastNode : TypeCastNode
+ internal class StrongTypeCastNode : TypeCastNode
{
private Func _cast;
diff --git a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
index e3878b5bc6..ec44eeb38f 100644
--- a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
+++ b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
@@ -19,6 +19,7 @@
+
diff --git a/src/Markup/Avalonia.Markup/Data/Binding.cs b/src/Markup/Avalonia.Markup/Data/Binding.cs
index 66907f33d0..37e7be5e3f 100644
--- a/src/Markup/Avalonia.Markup/Data/Binding.cs
+++ b/src/Markup/Avalonia.Markup/Data/Binding.cs
@@ -56,7 +56,7 @@ namespace Avalonia.Data
///
public Func? TypeResolver { get; set; }
- protected override ExpressionObserver CreateExpressionObserver(AvaloniaObject target, AvaloniaProperty? targetProperty, object? anchor, bool enableDataValidation)
+ private protected override ExpressionObserver CreateExpressionObserver(AvaloniaObject target, AvaloniaProperty? targetProperty, object? anchor, bool enableDataValidation)
{
_ = target ?? throw new ArgumentNullException(nameof(target));
diff --git a/src/Markup/Avalonia.Markup/Data/BindingBase.cs b/src/Markup/Avalonia.Markup/Data/BindingBase.cs
index 90f312a249..8c8c50763b 100644
--- a/src/Markup/Avalonia.Markup/Data/BindingBase.cs
+++ b/src/Markup/Avalonia.Markup/Data/BindingBase.cs
@@ -70,7 +70,7 @@ namespace Avalonia.Data
public WeakReference? NameScope { get; set; }
- protected abstract ExpressionObserver CreateExpressionObserver(
+ private protected abstract ExpressionObserver CreateExpressionObserver(
AvaloniaObject target,
AvaloniaProperty? targetProperty,
object? anchor,
@@ -127,7 +127,7 @@ namespace Avalonia.Data
return new InstancedBinding(subject, Mode, Priority);
}
- protected ExpressionObserver CreateDataContextObserver(
+ private protected ExpressionObserver CreateDataContextObserver(
AvaloniaObject target,
ExpressionNode node,
bool targetIsDataContext,
@@ -162,7 +162,7 @@ namespace Avalonia.Data
}
}
- protected ExpressionObserver CreateElementObserver(
+ private protected ExpressionObserver CreateElementObserver(
StyledElement target,
string elementName,
ExpressionNode node)
@@ -178,7 +178,7 @@ namespace Avalonia.Data
return result;
}
- protected ExpressionObserver CreateFindAncestorObserver(
+ private protected ExpressionObserver CreateFindAncestorObserver(
StyledElement target,
RelativeSource relativeSource,
ExpressionNode node)
@@ -211,7 +211,7 @@ namespace Avalonia.Data
null);
}
- protected ExpressionObserver CreateSourceObserver(
+ private protected ExpressionObserver CreateSourceObserver(
object source,
ExpressionNode node)
{
@@ -220,7 +220,7 @@ namespace Avalonia.Data
return new ExpressionObserver(source, node);
}
- protected ExpressionObserver CreateTemplatedParentObserver(
+ private protected ExpressionObserver CreateTemplatedParentObserver(
AvaloniaObject target,
ExpressionNode node)
{
diff --git a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs
index 1515ff2c90..993f63b4d3 100644
--- a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs
+++ b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs
@@ -85,8 +85,8 @@ namespace Avalonia.Data
var children = Bindings.Select(x => x.Initiate(target, null));
- var input = children.Select(x => x?.Observable!)
- .Where(x => x is not null)
+ var input = children.Select(x => x?.Source)
+ .Where(x => x is not null)!
.CombineLatest()
.Select(x => ConvertValue(x, targetType, converter))
.Where(x => x != BindingOperations.DoNothing);
diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionObserverBuilder.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionObserverBuilder.cs
index 00f40dfcd3..97e9698c13 100644
--- a/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionObserverBuilder.cs
+++ b/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionObserverBuilder.cs
@@ -6,7 +6,7 @@ using Avalonia.Utilities;
namespace Avalonia.Markup.Parsers
{
- public static class ExpressionObserverBuilder
+ internal static class ExpressionObserverBuilder
{
[RequiresUnreferencedCode(TrimmingMessages.ReflectionBindingRequiresUnreferencedCodeMessage)]
internal static (ExpressionNode Node, SourceMode Mode) Parse(string expression, bool enableValidation = false, Func? typeResolver = null,
diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/ElementNameNode.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/ElementNameNode.cs
index 4fc17e440b..e676c74879 100644
--- a/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/ElementNameNode.cs
+++ b/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/ElementNameNode.cs
@@ -6,7 +6,7 @@ using Avalonia.Reactive;
namespace Avalonia.Markup.Parsers.Nodes
{
- public class ElementNameNode : ExpressionNode
+ internal class ElementNameNode : ExpressionNode
{
private readonly WeakReference _nameScope;
private readonly string _name;
diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/FindAncestorNode.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/FindAncestorNode.cs
index ffbd34d492..383a160814 100644
--- a/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/FindAncestorNode.cs
+++ b/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/FindAncestorNode.cs
@@ -5,7 +5,7 @@ using Avalonia.Reactive;
namespace Avalonia.Markup.Parsers.Nodes
{
- public class FindAncestorNode : ExpressionNode
+ internal class FindAncestorNode : ExpressionNode
{
private readonly int _level;
private readonly Type? _ancestorType;
diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/SelfNode.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/SelfNode.cs
index 1cd233c68a..2cb87efa65 100644
--- a/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/SelfNode.cs
+++ b/src/Markup/Avalonia.Markup/Markup/Parsers/Nodes/SelfNode.cs
@@ -2,7 +2,7 @@
namespace Avalonia.Markup.Parsers.Nodes
{
- public class SelfNode : ExpressionNode
+ internal class SelfNode : ExpressionNode
{
public override string Description => "$self";
}
diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingTests.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingTests.cs
index 656c2cbbbc..3ba8e8354d 100644
--- a/tests/Avalonia.Markup.UnitTests/Data/BindingTests.cs
+++ b/tests/Avalonia.Markup.UnitTests/Data/BindingTests.cs
@@ -334,7 +334,7 @@ namespace Avalonia.Markup.UnitTests.Data
Path = "Foo",
};
- var result = binding.Initiate(target, TextBox.TextProperty).Value;
+ var result = binding.Initiate(target, TextBox.TextProperty).Source;
Assert.IsType(((BindingExpression)result).Converter);
}
@@ -350,7 +350,7 @@ namespace Avalonia.Markup.UnitTests.Data
Path = "Foo",
};
- var result = binding.Initiate(target, TextBox.TextProperty).Value;
+ var result = binding.Initiate(target, TextBox.TextProperty).Source;
Assert.Same(converter.Object, ((BindingExpression)result).Converter);
}
@@ -367,7 +367,7 @@ namespace Avalonia.Markup.UnitTests.Data
Path = "Bar",
};
- var result = binding.Initiate(target, TextBox.TextProperty).Value;
+ var result = binding.Initiate(target, TextBox.TextProperty).Source;
Assert.Same("foo", ((BindingExpression)result).ConverterParameter);
}
diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Converters.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Converters.cs
index 2a0750b131..680c49d098 100644
--- a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Converters.cs
+++ b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Converters.cs
@@ -24,7 +24,7 @@ namespace Avalonia.Markup.UnitTests.Data
var expressionObserver = (BindingExpression)target.Initiate(
textBlock,
- TextBlock.TextProperty).Observable;
+ TextBlock.TextProperty).Source;
Assert.Same(StringConverters.IsNullOrEmpty, expressionObserver.Converter);
}
@@ -46,7 +46,7 @@ namespace Avalonia.Markup.UnitTests.Data
var expressionObserver = (BindingExpression)target.Initiate(
textBlock,
- TextBlock.TextProperty).Observable;
+ TextBlock.TextProperty).Source;
Assert.IsType(expressionObserver.Converter);
}
@@ -69,7 +69,7 @@ namespace Avalonia.Markup.UnitTests.Data
var expressionObserver = (BindingExpression)target.Initiate(
textBlock,
- TextBlock.TagProperty).Observable;
+ TextBlock.TagProperty).Source;
Assert.IsType(expressionObserver.Converter);
}
@@ -92,7 +92,7 @@ namespace Avalonia.Markup.UnitTests.Data
var expressionObserver = (BindingExpression)target.Initiate(
textBlock,
- TextBlock.MarginProperty).Observable;
+ TextBlock.MarginProperty).Source;
Assert.Same(DefaultValueConverter.Instance, expressionObserver.Converter);
}
diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_DataValidation.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_DataValidation.cs
index 45deb97f51..505eddb146 100644
--- a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_DataValidation.cs
+++ b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_DataValidation.cs
@@ -20,7 +20,7 @@ namespace Avalonia.Markup.UnitTests.Data
var target = new Binding(nameof(Class1.Foo));
var instanced = target.Initiate(textBlock, TextBlock.TextProperty, enableDataValidation: false);
- var subject = (BindingExpression)instanced.Value;
+ var subject = (BindingExpression)instanced.Source;
object result = null;
subject.Subscribe(x => result = x);
@@ -38,7 +38,7 @@ namespace Avalonia.Markup.UnitTests.Data
var target = new Binding(nameof(Class1.Foo));
var instanced = target.Initiate(textBlock, TextBlock.TextProperty, enableDataValidation: true);
- var subject = (BindingExpression)instanced.Value;
+ var subject = (BindingExpression)instanced.Source;
object result = null;
subject.Subscribe(x => result = x);
@@ -56,7 +56,7 @@ namespace Avalonia.Markup.UnitTests.Data
var target = new Binding(nameof(Class1.Foo)) { Priority = BindingPriority.Template };
var instanced = target.Initiate(textBlock, TextBlock.TextProperty, enableDataValidation: true);
- var subject = (BindingExpression)instanced.Value;
+ var subject = (BindingExpression)instanced.Source;
object result = null;
subject.Subscribe(x => result = x);
diff --git a/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs
index a7ef2c4e4d..bf9631760a 100644
--- a/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs
+++ b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs
@@ -30,7 +30,7 @@ namespace Avalonia.Markup.UnitTests.Data
};
var target = new Control { DataContext = source };
- var observable = binding.Initiate(target, null).Observable;
+ var observable = binding.Initiate(target, null).Source;
var result = await observable.Take(1);
Assert.Equal("1,2,3", result);
@@ -59,7 +59,7 @@ namespace Avalonia.Markup.UnitTests.Data
};
var target = new Control { DataContext = source };
- var observable = binding.Initiate(target, null).Observable;
+ var observable = binding.Initiate(target, null).Source;
var result = await observable.Take(1);
Assert.Equal("1,2,3", result);