Browse Source
- Don't log an error when the target for the root ExpressionNode is null. This is usually because the `DataContext` hasn't been set up yet and it spewed a load of useless error messages. - Add a Description field to `ExpressionObserver` that can be used in the case of e.g. #control bindings to record the whole expression (with the "#control" part) rather than just the part tracked by the `ExpressionObserver`.pull/691/head
14 changed files with 216 additions and 159 deletions
@ -1,15 +0,0 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System; |
|||
|
|||
namespace Avalonia.Data |
|||
{ |
|||
/// <summary>
|
|||
/// An exception returned through <see cref="BindingNotification"/> signalling that a
|
|||
/// requested binding expression could not be evaluated.
|
|||
/// </summary>
|
|||
public class BindingBrokenException : Exception |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System; |
|||
|
|||
namespace Avalonia.Data |
|||
{ |
|||
/// <summary>
|
|||
/// An exception returned through <see cref="BindingNotification"/> signalling that a
|
|||
/// requested binding expression could not be evaluated because of a null in one of the links
|
|||
/// of the binding chain.
|
|||
/// </summary>
|
|||
public class BindingChainNullException : Exception |
|||
{ |
|||
private string _message; |
|||
|
|||
/// <summary>
|
|||
/// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
|
|||
/// </summary>
|
|||
public BindingChainNullException() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
|
|||
/// </summary>
|
|||
public BindingChainNullException(string message) |
|||
{ |
|||
_message = message; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
|
|||
/// </summary>
|
|||
/// <param name="expression">The expression.</param>
|
|||
/// <param name="expressionNullPoint">
|
|||
/// The point in the expression at which the null was encountered.
|
|||
/// </param>
|
|||
public BindingChainNullException(string expression, string expressionNullPoint) |
|||
{ |
|||
Expression = expression; |
|||
ExpressionNullPoint = expressionNullPoint; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the expression that could not be evaluated.
|
|||
/// </summary>
|
|||
public string Expression { get; protected set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the point in the expression at which the null was encountered.
|
|||
/// </summary>
|
|||
public string ExpressionNullPoint { get; protected set; } |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string Message |
|||
{ |
|||
get |
|||
{ |
|||
if (_message == null) |
|||
{ |
|||
_message = BuildMessage(); |
|||
} |
|||
|
|||
return _message; |
|||
} |
|||
} |
|||
|
|||
private string BuildMessage() |
|||
{ |
|||
if (Expression != null && ExpressionNullPoint != null) |
|||
{ |
|||
return $"'{ExpressionNullPoint}' is null in expression '{Expression}'."; |
|||
} |
|||
else if (ExpressionNullPoint != null) |
|||
{ |
|||
return $"'{ExpressionNullPoint}' is null in expression."; |
|||
} |
|||
else |
|||
{ |
|||
return "Null encountered in binding expression."; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,65 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Data; |
|||
|
|||
namespace Avalonia.Markup.Data |
|||
{ |
|||
public class MarkupBindingBrokenException : BindingBrokenException |
|||
{ |
|||
private string _message; |
|||
|
|||
public MarkupBindingBrokenException() |
|||
{ |
|||
} |
|||
|
|||
public MarkupBindingBrokenException(string message) |
|||
{ |
|||
_message = message; |
|||
} |
|||
|
|||
internal MarkupBindingBrokenException(ExpressionNode node) |
|||
{ |
|||
Nodes.Add(node.Description); |
|||
} |
|||
|
|||
public override string Message |
|||
{ |
|||
get |
|||
{ |
|||
if (_message != null) |
|||
{ |
|||
return _message; |
|||
} |
|||
else |
|||
{ |
|||
return _message = BuildMessage(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
internal string Expression { get; set; } |
|||
internal IList<string> Nodes { get; } = new List<string>(); |
|||
|
|||
private string BuildMessage() |
|||
{ |
|||
if (Nodes.Count == 0) |
|||
{ |
|||
return "The binding chain was broken."; |
|||
} |
|||
else if (Nodes.Count == 1) |
|||
{ |
|||
return $"'{Nodes[0]}' is null in expression '{Expression}'."; |
|||
} |
|||
else |
|||
{ |
|||
var brokenPath = string.Join(".", Nodes.Skip(1).Reverse()) |
|||
.Replace(".!", "!") |
|||
.Replace(".[", "["); |
|||
return $"'{brokenPath}' is null in expression '{Expression}'."; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Avalonia.Data; |
|||
|
|||
namespace Avalonia.Markup.Data |
|||
{ |
|||
internal class MarkupBindingChainNullException : BindingChainNullException |
|||
{ |
|||
private IList<string> _nodes = new List<string>(); |
|||
|
|||
public MarkupBindingChainNullException() |
|||
{ |
|||
} |
|||
|
|||
public MarkupBindingChainNullException(string expression, string expressionNullPoint) |
|||
: base(expression, expressionNullPoint) |
|||
{ |
|||
_nodes = null; |
|||
} |
|||
|
|||
public bool HasNodes => _nodes.Count > 0; |
|||
public void AddNode(string node) => _nodes.Add(node); |
|||
|
|||
public void Commit(string expression) |
|||
{ |
|||
Expression = expression; |
|||
ExpressionNullPoint = string.Join(".", _nodes.Reverse()) |
|||
.Replace(".!", "!") |
|||
.Replace(".[", "["); |
|||
_nodes = null; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue