Browse Source
This will replace BindingError and IValidationStatus for bindings that want to notify binding/validation errors. Still WIP.pull/691/head
committed by
Steven Kirk
21 changed files with 266 additions and 136 deletions
@ -1,59 +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>
|
|||
/// Represents a recoverable binding error.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// When produced by a binding source observable, informs the binding system that an error
|
|||
/// occurred. It can also provide an optional fallback value to be pushed to the binding
|
|||
/// target.
|
|||
///
|
|||
/// Instead of using <see cref="BindingError"/>, one could simply not push a value (in the
|
|||
/// case of a no fallback value) or push a fallback value, but BindingError also causes an
|
|||
/// error to be logged with the correct binding target.
|
|||
/// </remarks>
|
|||
public class BindingError |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BindingError"/> class.
|
|||
/// </summary>
|
|||
/// <param name="exception">An exception describing the binding error.</param>
|
|||
public BindingError(Exception exception) |
|||
{ |
|||
Exception = exception; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BindingError"/> class.
|
|||
/// </summary>
|
|||
/// <param name="exception">An exception describing the binding error.</param>
|
|||
/// <param name="fallbackValue">The fallback value.</param>
|
|||
public BindingError(Exception exception, object fallbackValue) |
|||
{ |
|||
Exception = exception; |
|||
FallbackValue = fallbackValue; |
|||
UseFallbackValue = true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the exception describing the binding error.
|
|||
/// </summary>
|
|||
public Exception Exception { get; } |
|||
|
|||
/// <summary>
|
|||
/// Get the fallback value.
|
|||
/// </summary>
|
|||
public object FallbackValue { get; } |
|||
|
|||
/// <summary>
|
|||
/// Get a value indicating whether the fallback value should be pushed to the binding
|
|||
/// target.
|
|||
/// </summary>
|
|||
public bool UseFallbackValue { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,169 @@ |
|||
// 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>
|
|||
/// Defines the types of binding errors for a <see cref="BindingNotification"/>.
|
|||
/// </summary>
|
|||
public enum BindingErrorType |
|||
{ |
|||
/// <summary>
|
|||
/// There was no error.
|
|||
/// </summary>
|
|||
None, |
|||
|
|||
/// <summary>
|
|||
/// There was a binding error.
|
|||
/// </summary>
|
|||
Error, |
|||
|
|||
/// <summary>
|
|||
/// There was a data validation error.
|
|||
/// </summary>
|
|||
DataValidationError, |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Represents a binding notification that can be a valid binding value, or a binding or
|
|||
/// data validation error.
|
|||
/// </summary>
|
|||
public class BindingNotification : IValidationStatus |
|||
{ |
|||
/// <summary>
|
|||
/// A binding notification representing the null value.
|
|||
/// </summary>
|
|||
public static readonly BindingNotification Null = |
|||
new BindingNotification(null); |
|||
|
|||
/// <summary>
|
|||
/// A binding notification representing <see cref="AvaloniaProperty.UnsetValue"/>.
|
|||
/// </summary>
|
|||
public static readonly BindingNotification UnsetValue = |
|||
new BindingNotification(AvaloniaProperty.UnsetValue); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BindingNotification"/> class.
|
|||
/// </summary>
|
|||
/// <param name="value">The binding value.</param>
|
|||
public BindingNotification(object value) |
|||
{ |
|||
Value = value; |
|||
HasValue = true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BindingNotification"/> class.
|
|||
/// </summary>
|
|||
/// <param name="error">The binding error.</param>
|
|||
/// <param name="errorType">The type of the binding error.</param>
|
|||
public BindingNotification(Exception error, BindingErrorType errorType) |
|||
{ |
|||
if (errorType == BindingErrorType.None) |
|||
{ |
|||
throw new ArgumentException($"'errorType' may not be None"); |
|||
} |
|||
|
|||
Error = error; |
|||
ErrorType = errorType; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BindingNotification"/> class.
|
|||
/// </summary>
|
|||
/// <param name="error">The binding error.</param>
|
|||
/// <param name="errorType">The type of the binding error.</param>
|
|||
/// <param name="fallbackValue">The fallback value.</param>
|
|||
public BindingNotification(Exception error, BindingErrorType errorType, object fallbackValue) |
|||
: this(error) |
|||
{ |
|||
Value = fallbackValue; |
|||
HasValue = true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the value that should be passed to the target when <see cref="HasValue"/>
|
|||
/// is true.
|
|||
/// </summary>
|
|||
public object Value { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether <see cref="Value"/> should be pushed to the target.
|
|||
/// </summary>
|
|||
public bool HasValue { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the error that occurred on the source, if any.
|
|||
/// </summary>
|
|||
public Exception Error { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the type of error that <see cref="Error"/> represents, if any.
|
|||
/// </summary>
|
|||
public BindingErrorType ErrorType { get; } |
|||
|
|||
bool IValidationStatus.IsValid => ErrorType == BindingErrorType.None; |
|||
|
|||
public static bool operator ==(BindingNotification a, BindingNotification b) |
|||
{ |
|||
if (object.ReferenceEquals(a, b)) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
if ((object)a == null || (object)b == null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return a.HasValue == b.HasValue && |
|||
a.ErrorType == b.ErrorType && |
|||
(!a.HasValue || object.Equals(a.Value, b.Value)) && |
|||
(a.ErrorType == BindingErrorType.None || object.Equals(a.Error, b.Error)); |
|||
} |
|||
|
|||
public static bool operator !=(BindingNotification a, BindingNotification b) |
|||
{ |
|||
return !(a == b); |
|||
} |
|||
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return Equals(obj as BindingNotification); |
|||
} |
|||
|
|||
public bool Equals(BindingNotification other) |
|||
{ |
|||
return this == other; |
|||
} |
|||
|
|||
public override int GetHashCode() |
|||
{ |
|||
return base.GetHashCode(); |
|||
} |
|||
|
|||
public BindingNotification WithError(Exception e) |
|||
{ |
|||
if (e == null) |
|||
{ |
|||
return this; |
|||
} |
|||
|
|||
if (Error != null) |
|||
{ |
|||
e = new AggregateException(Error, e); |
|||
} |
|||
|
|||
if (HasValue) |
|||
{ |
|||
return new BindingNotification(e, BindingErrorType.Error, Value); |
|||
} |
|||
else |
|||
{ |
|||
return new BindingNotification(e, BindingErrorType.Error, Value); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue