Browse Source

Fix StackOverflow in Negation Binding. Fixes #1213

pull/1214/head
Jeremy Koritzinsky 9 years ago
parent
commit
54e8187a70
  1. 19
      src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs
  2. 11
      src/Markup/Avalonia.Markup/Data/ITransformNode.cs
  3. 13
      src/Markup/Avalonia.Markup/Data/LogicalNotNode.cs
  4. 20
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Negation.cs

19
src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs

@ -154,7 +154,24 @@ namespace Avalonia.Markup.Data
/// </returns>
public bool SetValue(object value, BindingPriority priority = BindingPriority.LocalValue)
{
return (Leaf as ISettableNode)?.SetTargetValue(value, priority) ?? false;
if (Leaf is ISettableNode settable)
{
var node = _node;
while (node != null)
{
if (node is ITransformNode transform)
{
value = transform.Transform(value);
if (value is BindingNotification)
{
return false;
}
}
node = node.Next;
}
return settable.SetTargetValue(value, priority);
}
return false;
}
/// <summary>

11
src/Markup/Avalonia.Markup/Data/ITransformNode.cs

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Avalonia.Markup.Data
{
interface ITransformNode
{
object Transform(object value);
}
}

13
src/Markup/Avalonia.Markup/Data/LogicalNotNode.cs

@ -7,7 +7,7 @@ using Avalonia.Data;
namespace Avalonia.Markup.Data
{
internal class LogicalNotNode : ExpressionNode
internal class LogicalNotNode : ExpressionNode, ITransformNode
{
public override string Description => "!";
@ -61,5 +61,16 @@ namespace Avalonia.Markup.Data
return AvaloniaProperty.UnsetValue;
}
public object Transform(object value)
{
var originalType = value.GetType();
var negated = Negate(value);
if (negated is BindingNotification)
{
return negated;
}
return Convert.ChangeType(negated, originalType);
}
}
}

20
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Negation.cs

@ -105,14 +105,32 @@ namespace Avalonia.Markup.UnitTests.Data
}
[Fact]
public void SetValue_Should_Return_False()
public void SetValue_Should_Return_False_For_Invalid_Value()
{
var data = new { Foo = "foo" };
var target = new ExpressionObserver(data, "!Foo");
target.Subscribe(_ => { });
Assert.False(target.SetValue("bar"));
GC.KeepAlive(data);
}
[Fact]
public void Can_SetValue_For_Valid_Value()
{
var data = new Test { Foo = true };
var target = new ExpressionObserver(data, "!Foo");
target.Subscribe(_ => { });
Assert.True(target.SetValue(true));
Assert.False(data.Foo);
}
private class Test
{
public bool Foo { get; set; }
}
}
}

Loading…
Cancel
Save