Browse Source

WIP

pull/494/merge
Steven Kirk 11 years ago
parent
commit
b63a5b3e7c
  1. 9
      src/Markup/Perspex.Markup/DefaultValueConverter.cs
  2. 31
      src/Perspex.Base/Data/BindingError.cs
  3. 5
      src/Perspex.Base/PerspexObject.cs
  4. 26
      tests/Perspex.Base.UnitTests/PerspexObjectTests_Binding.cs
  5. 26
      tests/Perspex.Base.UnitTests/PerspexObjectTests_Direct.cs
  6. 3
      tests/Perspex.Markup.UnitTests/DefaultValueConverterTests.cs

9
src/Markup/Perspex.Markup/DefaultValueConverter.cs

@ -5,6 +5,7 @@ using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Perspex.Data;
using Perspex.Logging;
using Perspex.Utilities;
@ -42,12 +43,8 @@ namespace Perspex.Markup
if (value != null)
{
Logger.Error(
LogArea.Binding,
this,
"Could not convert {Value} to {Type}",
value,
targetType);
var message = $"Could not convert {value} to {targetType}";
return new BindingError(new InvalidCastException(message));
}
return PerspexProperty.UnsetValue;

31
src/Perspex.Base/Data/BindingError.cs

@ -10,8 +10,12 @@ namespace Perspex.Data
/// </summary>
/// <remarks>
/// 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.
/// 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
{
@ -24,9 +28,32 @@ namespace Perspex.Data
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; }
}
}

5
src/Perspex.Base/PerspexObject.cs

@ -672,6 +672,11 @@ namespace Perspex
}
else
{
if (error.UseFallbackValue)
{
SetValue(property, error.FallbackValue);
}
Logger.Error(
LogArea.Binding,
this,

26
tests/Perspex.Base.UnitTests/PerspexObjectTests_Binding.cs

@ -267,6 +267,32 @@ namespace Perspex.Base.UnitTests
Assert.Equal("first", target2.GetValue(Class1.FooProperty));
}
[Fact]
public void BindingError_Does_Not_Cause_Target_Update()
{
var target = new Class1();
var source = new Subject<object>();
target.Bind(Class1.QuxProperty, source);
source.OnNext(6.7);
source.OnNext(new BindingError(new InvalidOperationException("Foo")));
Assert.Equal(6.7, target.GetValue(Class1.QuxProperty));
}
[Fact]
public void BindingError_With_FallbackValue_Causes_Target_Update()
{
var target = new Class1();
var source = new Subject<object>();
target.Bind(Class1.QuxProperty, source);
source.OnNext(6.7);
source.OnNext(new BindingError(new InvalidOperationException("Foo"), 8.9));
Assert.Equal(8.9, target.GetValue(Class1.QuxProperty));
}
[Fact]
public void Bind_Logs_BindingError()
{

26
tests/Perspex.Base.UnitTests/PerspexObjectTests_Direct.cs

@ -396,6 +396,32 @@ namespace Perspex.Base.UnitTests
Assert.True(raised);
}
[Fact]
public void BindingError_Does_Not_Cause_Target_Update()
{
var target = new Class1();
var source = new Subject<object>();
target.Bind(Class1.FooProperty, source);
source.OnNext("initial");
source.OnNext(new BindingError(new InvalidOperationException("Foo")));
Assert.Equal("initial", target.GetValue(Class1.FooProperty));
}
[Fact]
public void BindingError_With_FallbackValue_Causes_Target_Update()
{
var target = new Class1();
var source = new Subject<object>();
target.Bind(Class1.FooProperty, source);
source.OnNext("initial");
source.OnNext(new BindingError(new InvalidOperationException("Foo"), "fallback"));
Assert.Equal("fallback", target.GetValue(Class1.FooProperty));
}
[Fact]
public void Binding_To_Direct_Property_Logs_BindingError()
{

3
tests/Perspex.Markup.UnitTests/DefaultValueConverterTests.cs

@ -3,6 +3,7 @@
using System.Globalization;
using Perspex.Controls;
using Perspex.Data;
using Xunit;
namespace Perspex.Markup.UnitTests
@ -114,7 +115,7 @@ namespace Perspex.Markup.UnitTests
null,
CultureInfo.InvariantCulture);
Assert.Equal(PerspexProperty.UnsetValue, result);
Assert.IsType<BindingError>(result);
}
private enum TestEnum

Loading…
Cancel
Save