Browse Source

Make default binding Source = UnsetProperty.

Null is a theoretically valid value for `Source`; setting it to null shouldn't mean "use the data context".
refactor/bindingexpressions-in-valuestore
Steven Kirk 3 years ago
parent
commit
a7c1440326
  1. 4
      src/Avalonia.Base/Data/Core/ExpressionNodes/DataContextNode.cs
  2. 2
      src/Avalonia.Base/Data/Core/ExpressionNodes/ParentDataContextNode.cs
  3. 2
      src/Avalonia.Base/Data/Core/ExpressionNodes/TemplatedParentNode.cs
  4. 8
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
  5. 2
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs
  6. 12
      src/Markup/Avalonia.Markup/Data/Binding.cs

4
src/Avalonia.Base/Data/Core/ExpressionNodes/DataContextNode.cs

@ -5,6 +5,8 @@ namespace Avalonia.Data.Core.ExpressionNodes;
internal class DataContextNode : ExpressionNode, ISourceNode
{
public bool ShouldLogErrors => Value is not null;
public override void BuildString(StringBuilder builder)
{
// Nothing to add.
@ -12,7 +14,7 @@ internal class DataContextNode : ExpressionNode, ISourceNode
public object SelectSource(object? source, object target, object? anchor)
{
if (source is not null)
if (source != AvaloniaProperty.UnsetValue)
throw new NotSupportedException(
"DataContextNode is invalid in conjunction with a binding source.");
if (target is IDataContextProvider and AvaloniaObject)

2
src/Avalonia.Base/Data/Core/ExpressionNodes/ParentDataContextNode.cs

@ -19,7 +19,7 @@ internal class ParentDataContextNode : ExpressionNode, ISourceNode
public object SelectSource(object? source, object target, object? anchor)
{
if (source is not null)
if (source != AvaloniaProperty.UnsetValue)
throw new NotSupportedException(
"ParentDataContextNode is invalid in conjunction with a binding source.");
if (target is IDataContextProvider and AvaloniaObject)

2
src/Avalonia.Base/Data/Core/ExpressionNodes/TemplatedParentNode.cs

@ -12,7 +12,7 @@ internal class TemplatedParentNode : ExpressionNode, ISourceNode
public object SelectSource(object? source, object target, object? anchor)
{
if (source is not null)
if (source != AvaloniaProperty.UnsetValue)
throw new NotSupportedException(
"TemplatedParentNode is invalid in conjunction with a binding source.");
if (target is StyledElement)

8
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs

@ -50,14 +50,14 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
// If the binding isn't rooted (i.e. doesn't have a Source or start with $parent, $self,
// #elementName etc.) then we need to add a data context source node.
if (Source is null && !isRooted)
if (Source == AvaloniaProperty.UnsetValue && !isRooted)
nodes.Insert(0, ExpressionNodeFactory.CreateDataContext(targetProperty));
// If the first node is an ISourceNode then allow it to select the source; otherwise
// use the binding source if specified, falling back to the target.
var source = nodes.Count > 0 && nodes[0] is ISourceNode sn
? sn.SelectSource(Source, target, anchor ?? DefaultAnchor?.Target)
: Source ?? target;
: Source != AvaloniaProperty.UnsetValue? Source : target;
// Create the binding expression and wrap it in an InstancedBinding.
var expression = new BindingExpression(
@ -87,7 +87,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
/// </remarks>
internal BindingExpression CreateObservableForTreeDataTemplate(object source)
{
if (Source is not null)
if (Source != AvaloniaProperty.UnsetValue)
throw new NotSupportedException("Source bindings are not supported in this context.");
var nodes = new List<ExpressionNode>();
@ -109,7 +109,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
[ConstructorArgument("path")]
public CompiledBindingPath Path { get; set; }
public object? Source { get; set; }
public object? Source { get; set; } = AvaloniaProperty.UnsetValue;
public Type? DataType { get; set; }
}

2
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs

@ -54,7 +54,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
public BindingPriority Priority { get; set; } = BindingPriority.LocalValue;
public object? Source { get; set; }
public object? Source { get; set; } = AvaloniaProperty.UnsetValue;
public string? StringFormat { get; set; }

12
src/Markup/Avalonia.Markup/Data/Binding.cs

@ -47,7 +47,7 @@ namespace Avalonia.Data
/// <summary>
/// Gets or sets the source for the binding.
/// </summary>
public object? Source { get; set; }
public object? Source { get; set; } = AvaloniaProperty.UnsetValue;
/// <summary>
/// Gets or sets the binding path.
@ -85,14 +85,14 @@ namespace Avalonia.Data
// #elementName etc.) then we need to add a source node. The type of source node will
// depend on the ElementName and RelativeSource properties of the binding and if
// neither of those are set will default to a data context node.
if (Source is null && !isRooted && CreateSourceNode(targetProperty) is { } sourceNode)
if (Source == AvaloniaProperty.UnsetValue && !isRooted && CreateSourceNode(targetProperty) is { } sourceNode)
nodes.Insert(0, sourceNode);
// If the first node is an ISourceNode then allow it to select the source; otherwise
// use the binding source if specified, falling back to the target.
var source = nodes.Count > 0 && nodes[0] is ISourceNode sn
? sn.SelectSource(Source, target, anchor ?? DefaultAnchor?.Target)
: Source ?? target;
var source = nodes.Count > 0 && nodes[0] is ISourceNode sn ?
sn.SelectSource(Source, target, anchor ?? DefaultAnchor?.Target) :
Source != AvaloniaProperty.UnsetValue ? Source : target;
// Create the binding expression and wrap it in an InstancedBinding.
var expression = new BindingExpression(
@ -125,7 +125,7 @@ namespace Avalonia.Data
throw new NotSupportedException("ElementName bindings are not supported in this context.");
if (RelativeSource is not null && RelativeSource.Mode != RelativeSourceMode.DataContext)
throw new NotSupportedException("RelativeSource bindings are not supported in this context.");
if (Source is not null)
if (Source != AvaloniaProperty.UnsetValue)
throw new NotSupportedException("Source bindings are not supported in this context.");
var nodes = new List<ExpressionNode>();

Loading…
Cancel
Save