diff --git a/src/Perspex.Base/Data/BindingError.cs b/src/Perspex.Base/Data/BindingError.cs
new file mode 100644
index 0000000000..d29b06fea9
--- /dev/null
+++ b/src/Perspex.Base/Data/BindingError.cs
@@ -0,0 +1,32 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+
+namespace Perspex.Data
+{
+ ///
+ /// Represents a recoverable binding error.
+ ///
+ ///
+ /// When produced by a binding source observable, informs the binding system that an error
+ /// occurred. It causes a binding error to be logged: the value of the bound property will not
+ /// change.
+ ///
+ public class BindingError
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// An exception describing the binding error.
+ public BindingError(Exception exception)
+ {
+ Exception = exception;
+ }
+
+ ///
+ /// Gets the exception describing the binding error.
+ ///
+ public Exception Exception { get; }
+ }
+}
diff --git a/src/Perspex.Base/Perspex.Base.csproj b/src/Perspex.Base/Perspex.Base.csproj
index ae185b3abf..84dbd9a0d3 100644
--- a/src/Perspex.Base/Perspex.Base.csproj
+++ b/src/Perspex.Base/Perspex.Base.csproj
@@ -43,6 +43,7 @@
Properties\SharedAssemblyInfo.cs
+
diff --git a/src/Perspex.Base/PerspexObject.cs b/src/Perspex.Base/PerspexObject.cs
index 32f8eedc91..86ebb45921 100644
--- a/src/Perspex.Base/PerspexObject.cs
+++ b/src/Perspex.Base/PerspexObject.cs
@@ -403,9 +403,9 @@ namespace Perspex
IDisposable subscription = null;
subscription = source
- .Select(x => TypeUtilities.CastOrDefault(x, property.PropertyType))
+ .Select(x => CastOrDefault(x, property.PropertyType))
.Do(_ => { }, () => s_directBindings.Remove(subscription))
- .Subscribe(x => SetValue(property, x));
+ .Subscribe(x => DirectBindingSet(property, x));
s_directBindings.Add(subscription);
@@ -587,6 +587,27 @@ namespace Perspex
}
}
+ ///
+ /// Tries to cast a value to a type, taking into account that the value may be a
+ /// .
+ ///
+ /// The value.
+ /// The type.
+ /// The cast value, or a .
+ private static object CastOrDefault(object value, Type type)
+ {
+ var error = value as BindingError;
+
+ if (error == null)
+ {
+ return TypeUtilities.CastOrDefault(value, type);
+ }
+ else
+ {
+ return error;
+ }
+ }
+
///
/// Creates a for a .
///
@@ -635,6 +656,33 @@ namespace Perspex
return result;
}
+ ///
+ /// Sets a property value for a direct property binding.
+ ///
+ /// The property.
+ /// The value.
+ ///
+ private void DirectBindingSet(PerspexProperty property, object value)
+ {
+ var error = value as BindingError;
+
+ if (error == null)
+ {
+ SetValue(property, value);
+ }
+ else
+ {
+ Logger.Error(
+ LogArea.Binding,
+ this,
+ "Error binding to {Target}.{PropertyName}: {Message}",
+ property.Name,
+ property.PropertyType,
+ value,
+ value.GetType());
+ }
+ }
+
///
/// Converts an unset value to the default value for a direct property.
///
diff --git a/src/Perspex.Base/PriorityBindingEntry.cs b/src/Perspex.Base/PriorityBindingEntry.cs
index a17080f0f4..3fcb77f950 100644
--- a/src/Perspex.Base/PriorityBindingEntry.cs
+++ b/src/Perspex.Base/PriorityBindingEntry.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using Perspex.Data;
namespace Perspex
{
@@ -63,10 +64,12 @@ namespace Perspex
/// The binding.
/// Called when the binding changes.
/// Called when the binding completes.
+ /// Called when a binding error occurs.
public void Start(
IObservable