Browse Source

Merge branch 'master' into pr/763

pull/763/head
Steven Kirk 10 years ago
parent
commit
8955a20cf6
  1. 2
      src/Avalonia.Base/Avalonia.Base.csproj
  2. 57
      src/Avalonia.Base/Data/BindingChainException.cs
  3. 2
      src/Avalonia.Controls/TextBox.cs
  4. 25
      src/Avalonia.Input/AccessKeyHandler.cs
  5. 2
      src/Markup/Avalonia.Markup.Xaml/OmniXAML
  6. 9
      src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
  7. 57
      src/Markup/Avalonia.Markup/Data/ExpressionNode.cs
  8. 14
      src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs
  9. 42
      src/Markup/Avalonia.Markup/Data/MarkupBindingChainException.cs
  10. 33
      src/Markup/Avalonia.Markup/Data/MarkupBindingChainNullException.cs
  11. 10
      src/Markup/Avalonia.Markup/Data/Parsers/ExpressionParser.cs
  12. 4
      src/Markup/Avalonia.Markup/Data/Plugins/IStreamPlugin.cs
  13. 18
      src/Markup/Avalonia.Markup/Data/Plugins/ObservableStreamPlugin.cs
  14. 4
      src/Markup/Avalonia.Markup/Data/Plugins/TaskStreamPlugin.cs
  15. 31
      src/Markup/Avalonia.Markup/Data/StreamNode.cs
  16. 2
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_DataValidation.cs
  17. 51
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Observable.cs
  18. 4
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Property.cs
  19. 15
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Task.cs

2
src/Avalonia.Base/Avalonia.Base.csproj

@ -44,7 +44,7 @@
<Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Data\BindingChainNullException.cs" />
<Compile Include="Data\BindingChainException.cs" />
<Compile Include="Data\BindingNotification.cs" />
<Compile Include="Data\IndexerBinding.cs" />
<Compile Include="Diagnostics\INotifyCollectionChangedDebug.cs" />

57
src/Avalonia.Base/Data/BindingChainNullException.cs → src/Avalonia.Base/Data/BindingChainException.cs

@ -10,36 +10,39 @@ namespace Avalonia.Data
/// 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
public class BindingChainException : Exception
{
private string _message;
/// <summary>
/// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
/// Initalizes a new instance of the <see cref="BindingChainException"/> class.
/// </summary>
public BindingChainNullException()
public BindingChainException()
{
}
/// <summary>
/// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
/// Initalizes a new instance of the <see cref="BindingChainException"/> class.
/// </summary>
public BindingChainNullException(string message)
/// <param name="message">The error message.</param>
public BindingChainException(string message)
{
_message = message;
}
/// <summary>
/// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
/// Initalizes a new instance of the <see cref="BindingChainException"/> class.
/// </summary>
/// <param name="message">The error message.</param>
/// <param name="expression">The expression.</param>
/// <param name="expressionNullPoint">
/// The point in the expression at which the null was encountered.
/// <param name="errorPoint">
/// The point in the expression at which the error was encountered.
/// </param>
public BindingChainNullException(string expression, string expressionNullPoint)
public BindingChainException(string message, string expression, string errorPoint)
{
_message = message;
Expression = expression;
ExpressionNullPoint = expressionNullPoint;
ExpressionErrorPoint = errorPoint;
}
/// <summary>
@ -48,37 +51,27 @@ namespace Avalonia.Data
public string Expression { get; protected set; }
/// <summary>
/// Gets the point in the expression at which the null was encountered.
/// Gets the point in the expression at which the error occured.
/// </summary>
public string ExpressionNullPoint { get; protected set; }
public string ExpressionErrorPoint { get; protected set; }
/// <inheritdoc/>
public override string Message
{
get
{
if (_message == null)
if (Expression != null && ExpressionErrorPoint != null)
{
_message = BuildMessage();
return $"{_message} in expression '{Expression}' at '{ExpressionErrorPoint}'.";
}
else if (ExpressionErrorPoint != null)
{
return $"{_message} in expression '{ExpressionErrorPoint}'.";
}
else
{
return $"{_message} in expression.";
}
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.";
}
}
}

2
src/Avalonia.Controls/TextBox.cs

@ -547,7 +547,7 @@ namespace Avalonia.Controls
var exceptions = aggregate == null ?
(IEnumerable<Exception>)new[] { exception } :
aggregate.InnerExceptions;
var filtered = exceptions.Where(x => !(x is BindingChainNullException)).ToList();
var filtered = exceptions.Where(x => !(x is BindingChainException)).ToList();
if (filtered.Count > 0)
{

25
src/Avalonia.Input/AccessKeyHandler.cs

@ -43,6 +43,16 @@ namespace Avalonia.Input
/// </summary>
private bool _ignoreAltUp;
/// <summary>
/// Whether the AltKey is down.
/// </summary>
private bool _altIsDown;
/// <summary>
/// Element to restore folowing AltKey taking focus.
/// </summary>
private IInputElement _restoreFocusElement;
/// <summary>
/// Gets or sets the window's main menu.
/// </summary>
@ -110,8 +120,14 @@ namespace Avalonia.Input
{
if (e.Key == Key.LeftAlt)
{
_altIsDown = true;
if (MainMenu == null || !MainMenu.IsOpen)
{
// TODO: Use FocusScopes to store the current element and restore it when context menu is closed.
// Save currently focused input element.
_restoreFocusElement = FocusManager.Instance.Current;
// When Alt is pressed without a main menu, or with a closed main menu, show
// access key markers in the window (i.e. "_File").
_owner.ShowAccessKeys = _showingAccessKeys = true;
@ -121,11 +137,18 @@ namespace Avalonia.Input
// If the Alt key is pressed and the main menu is open, close the main menu.
CloseMenu();
_ignoreAltUp = true;
_restoreFocusElement?.Focus();
_restoreFocusElement = null;
}
// We always handle the Alt key.
e.Handled = true;
}
else if (_altIsDown)
{
_ignoreAltUp = true;
}
}
/// <summary>
@ -179,6 +202,8 @@ namespace Avalonia.Input
switch (e.Key)
{
case Key.LeftAlt:
_altIsDown = false;
if (_ignoreAltUp)
{
_ignoreAltUp = false;

2
src/Markup/Avalonia.Markup.Xaml/OmniXAML

@ -1 +1 @@
Subproject commit b122549406107170bbe6e67c0d6a1a4252beef77
Subproject commit 544af79d218127b4174da4be19896c5ca78eaa5d

9
src/Markup/Avalonia.Markup/Avalonia.Markup.csproj

@ -42,7 +42,8 @@
<Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Data\MarkupBindingChainNullException.cs" />
<Compile Include="Data\StreamNode.cs" />
<Compile Include="Data\MarkupBindingChainException.cs" />
<Compile Include="Data\CommonPropertyNames.cs" />
<Compile Include="Data\EmptyExpressionNode.cs" />
<Compile Include="Data\ExpressionNodeBuilder.cs" />
@ -63,9 +64,9 @@
<Compile Include="Data\Parsers\IdentifierParser.cs" />
<Compile Include="Data\Parsers\ExpressionParser.cs" />
<Compile Include="Data\Parsers\Reader.cs" />
<Compile Include="Data\Plugins\ObservableValuePlugin.cs" />
<Compile Include="Data\Plugins\TaskValuePlugin.cs" />
<Compile Include="Data\Plugins\IValuePlugin.cs" />
<Compile Include="Data\Plugins\ObservableStreamPlugin.cs" />
<Compile Include="Data\Plugins\TaskStreamPlugin.cs" />
<Compile Include="Data\Plugins\IStreamPlugin.cs" />
<Compile Include="Data\Plugins\PropertyAccessorBase.cs" />
<Compile Include="Data\Plugins\PropertyError.cs" />
<Compile Include="Data\Plugins\DataValidatiorBase.cs" />

57
src/Markup/Avalonia.Markup/Data/ExpressionNode.cs

@ -17,7 +17,6 @@ namespace Avalonia.Markup.Data
private WeakReference _target = UnsetReference;
private IDisposable _valueSubscription;
private IObserver<object> _observer;
private IDisposable _valuePluginSubscription;
public abstract string Description { get; }
public ExpressionNode Next { get; set; }
@ -37,7 +36,6 @@ namespace Avalonia.Markup.Data
{
_valueSubscription?.Dispose();
_valueSubscription = null;
_valuePluginSubscription?.Dispose();
_target = value;
if (running)
@ -63,8 +61,6 @@ namespace Avalonia.Markup.Data
{
_valueSubscription?.Dispose();
_valueSubscription = null;
_valuePluginSubscription?.Dispose();
_valuePluginSubscription = null;
nextSubscription?.Dispose();
_observer = null;
});
@ -92,7 +88,7 @@ namespace Avalonia.Markup.Data
protected virtual void NextValueChanged(object value)
{
var bindingBroken = BindingNotification.ExtractError(value) as MarkupBindingChainNullException;
var bindingBroken = BindingNotification.ExtractError(value) as MarkupBindingChainException;
bindingBroken?.AddNode(Description);
_observer.OnNext(value);
}
@ -115,25 +111,22 @@ namespace Avalonia.Markup.Data
source = StartListeningCore(_target);
}
return source.Subscribe(TargetValueChanged);
return source.Subscribe(ValueChanged);
}
private void TargetValueChanged(object value)
private void ValueChanged(object value)
{
var notification = value as BindingNotification;
if (notification == null)
{
if (!HandleSpecialValue(value))
if (Next != null)
{
if (Next != null)
{
Next.Target = new WeakReference(value);
}
else
{
_observer.OnNext(value);
}
Next.Target = new WeakReference(value);
}
else
{
_observer.OnNext(value);
}
}
else
@ -144,44 +137,22 @@ namespace Avalonia.Markup.Data
}
else if (notification.HasValue)
{
if (!HandleSpecialValue(notification.Value))
if (Next != null)
{
if (Next != null)
{
Next.Target = new WeakReference(notification.Value);
}
else
{
_observer.OnNext(value);
}
Next.Target = new WeakReference(notification.Value);
}
}
}
}
private bool HandleSpecialValue(object value)
{
if (_valuePluginSubscription == null)
{
var reference = new WeakReference(value);
foreach (var plugin in ExpressionObserver.ValueHandlers)
{
if (plugin.Match(reference))
else
{
_valuePluginSubscription = plugin.Start(reference)?.Subscribe(TargetValueChanged);
return true;
_observer.OnNext(value);
}
}
}
return false;
}
private BindingNotification TargetNullNotification()
{
return new BindingNotification(
new MarkupBindingChainNullException(),
new MarkupBindingChainException("Null value"),
BindingErrorType.Error,
AvaloniaProperty.UnsetValue);
}

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

@ -41,14 +41,14 @@ namespace Avalonia.Markup.Data
};
/// <summary>
/// An ordered collection of value handlers that can be used to customize the handling
/// of certain values.
/// An ordered collection of stream plugins that can be used to customize the behavior
/// of the '^' stream binding operator.
/// </summary>
public static readonly IList<IValuePlugin> ValueHandlers =
new List<IValuePlugin>
public static readonly IList<IStreamPlugin> StreamHandlers =
new List<IStreamPlugin>
{
new TaskValuePlugin(),
new ObservableValuePlugin(),
new TaskStreamPlugin(),
new ObservableStreamPlugin(),
};
private static readonly object UninitializedValue = new object();
@ -235,7 +235,7 @@ namespace Avalonia.Markup.Data
}
else
{
var broken = BindingNotification.ExtractError(o) as MarkupBindingChainNullException;
var broken = BindingNotification.ExtractError(o) as MarkupBindingChainException;
if (broken != null)
{

42
src/Markup/Avalonia.Markup/Data/MarkupBindingChainException.cs

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Data;
namespace Avalonia.Markup.Data
{
internal class MarkupBindingChainException : BindingChainException
{
private IList<string> _nodes = new List<string>();
public MarkupBindingChainException(string message)
: base(message)
{
}
public MarkupBindingChainException(string message, string node)
: base(message)
{
AddNode(node);
}
public MarkupBindingChainException(string message, string expression, string expressionNullPoint)
: base(message, 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;
ExpressionErrorPoint = string.Join(".", _nodes.Reverse())
.Replace(".!", "!")
.Replace(".[", "[")
.Replace(".^", "^");
_nodes = null;
}
}
}

33
src/Markup/Avalonia.Markup/Data/MarkupBindingChainNullException.cs

@ -1,33 +0,0 @@
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;
}
}
}

10
src/Markup/Avalonia.Markup/Data/Parsers/ExpressionParser.cs

@ -87,6 +87,11 @@ namespace Avalonia.Markup.Data.Parsers
{
return State.BeforeMember;
}
else if (ParseStreamOperator(r))
{
nodes.Add(new StreamNode());
return State.AfterMember;
}
else
{
var args = ArgumentListParser.Parse(r, '[', ']');
@ -161,6 +166,11 @@ namespace Avalonia.Markup.Data.Parsers
return !r.End && r.TakeIf('(');
}
private static bool ParseStreamOperator(Reader r)
{
return !r.End && r.TakeIf('^');
}
private enum State
{
Start,

4
src/Markup/Avalonia.Markup/Data/Plugins/IValuePlugin.cs → src/Markup/Avalonia.Markup/Data/Plugins/IStreamPlugin.cs

@ -6,9 +6,9 @@ using System;
namespace Avalonia.Markup.Data.Plugins
{
/// <summary>
/// Defines how values are observed by an <see cref="ExpressionObserver"/>.
/// Defines a plugin that handles the '^' stream binding operator.
/// </summary>
public interface IValuePlugin
public interface IStreamPlugin
{
/// <summary>
/// Checks whether this plugin handles the specified value.

18
src/Markup/Avalonia.Markup/Data/Plugins/ObservableValuePlugin.cs → src/Markup/Avalonia.Markup/Data/Plugins/ObservableStreamPlugin.cs

@ -2,32 +2,20 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Input;
using Avalonia.Data;
namespace Avalonia.Markup.Data.Plugins
{
/// <summary>
/// Handles binding to <see cref="IObservable{T}"/>s in an <see cref="ExpressionObserver"/>.
/// Handles binding to <see cref="IObservable{T}"/>s for the '^' stream binding operator.
/// </summary>
public class ObservableValuePlugin : IValuePlugin
public class ObservableStreamPlugin : IStreamPlugin
{
/// <summary>
/// Checks whether this plugin handles the specified value.
/// </summary>
/// <param name="reference">A weak reference to the value.</param>
/// <returns>True if the plugin can handle the value; otherwise false.</returns>
public virtual bool Match(WeakReference reference)
{
var target = reference.Target;
// ReactiveCommand is an IObservable but we want to bind to it, not its value.
return target is IObservable<object> && !(target is ICommand);
}
public virtual bool Match(WeakReference reference) => reference.Target is IObservable<object>;
/// <summary>
/// Starts producing output based on the specified value.

4
src/Markup/Avalonia.Markup/Data/Plugins/TaskValuePlugin.cs → src/Markup/Avalonia.Markup/Data/Plugins/TaskStreamPlugin.cs

@ -12,9 +12,9 @@ using Avalonia.Data;
namespace Avalonia.Markup.Data.Plugins
{
/// <summary>
/// Handles binding to <see cref="Task"/>s in an <see cref="ExpressionObserver"/>.
/// Handles binding to <see cref="Task"/>s for the '^' stream binding operator.
/// </summary>
public class TaskValuePlugin : IValuePlugin
public class TaskStreamPlugin : IStreamPlugin
{
/// <summary>
/// Checks whether this plugin handles the specified value.

31
src/Markup/Avalonia.Markup/Data/StreamNode.cs

@ -0,0 +1,31 @@
// 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;
using System.Globalization;
using Avalonia.Data;
using System.Reactive.Linq;
namespace Avalonia.Markup.Data
{
internal class StreamNode : ExpressionNode
{
public override string Description => "^";
protected override IObservable<object> StartListeningCore(WeakReference reference)
{
foreach (var plugin in ExpressionObserver.StreamHandlers)
{
if (plugin.Match(reference))
{
return plugin.Start(reference);
}
}
// TODO: Improve error.
return Observable.Return(new BindingNotification(
new MarkupBindingChainException("Stream operator applied to unsupported type", Description),
BindingErrorType.Error));
}
}
}

2
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_DataValidation.cs

@ -143,7 +143,7 @@ namespace Avalonia.Markup.UnitTests.Data
Assert.Equal(new[]
{
new BindingNotification(
new MarkupBindingChainNullException("Inner.MustBePositive", "Inner"),
new MarkupBindingChainException("Null value", "Inner.MustBePositive", "Inner"),
BindingErrorType.Error,
AvaloniaProperty.UnsetValue),
}, result);

51
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Observable.cs

@ -15,7 +15,7 @@ namespace Avalonia.Markup.UnitTests.Data
public class ExpressionObserverTests_Observable
{
[Fact]
public void Should_Get_Simple_Observable_Value()
public void Should_Not_Get_Observable_Value_Without_Modifier_Char()
{
using (var sync = UnitTestSynchronizationContext.Begin())
{
@ -28,6 +28,24 @@ namespace Avalonia.Markup.UnitTests.Data
source.OnNext("bar");
sync.ExecutePostedCallbacks();
Assert.Equal(new[] { source }, result);
}
}
[Fact]
public void Should_Get_Simple_Observable_Value()
{
using (var sync = UnitTestSynchronizationContext.Begin())
{
var source = new BehaviorSubject<string>("foo");
var data = new { Foo = source };
var target = new ExpressionObserver(data, "Foo^");
var result = new List<object>();
var sub = target.Subscribe(x => result.Add(x));
source.OnNext("bar");
sync.ExecutePostedCallbacks();
Assert.Equal(new[] { "foo", "bar" }, result);
}
}
@ -38,7 +56,7 @@ namespace Avalonia.Markup.UnitTests.Data
using (var sync = UnitTestSynchronizationContext.Begin())
{
var data = new Class1();
var target = new ExpressionObserver(data, "Next.Foo");
var target = new ExpressionObserver(data, "Next^.Foo");
var result = new List<object>();
var sub = target.Subscribe(x => result.Add(x));
@ -59,7 +77,7 @@ namespace Avalonia.Markup.UnitTests.Data
{
var source = new BehaviorSubject<string>("foo");
var data = new { Foo = source };
var target = new ExpressionObserver(data, "Foo", true);
var target = new ExpressionObserver(data, "Foo^", true);
var result = new List<object>();
var sub = target.Subscribe(x => result.Add(x));
@ -78,7 +96,7 @@ namespace Avalonia.Markup.UnitTests.Data
using (var sync = UnitTestSynchronizationContext.Begin())
{
var data = new Class1();
var target = new ExpressionObserver(data, "Next.Foo", true);
var target = new ExpressionObserver(data, "Next^.Foo", true);
var result = new List<object>();
var sub = target.Subscribe(x => result.Add(x));
@ -92,6 +110,31 @@ namespace Avalonia.Markup.UnitTests.Data
}
}
[Fact]
public void Should_Return_BindingNotification_If_Stream_Operator_Applied_To_Not_Supported_Type()
{
using (var sync = UnitTestSynchronizationContext.Begin())
{
var data = new Class2("foo");
var target = new ExpressionObserver(data, "Foo^", true);
var result = new List<object>();
var sub = target.Subscribe(x => result.Add(x));
sync.ExecutePostedCallbacks();
Assert.Equal(
new[]
{
new BindingNotification(
new MarkupBindingChainException("Stream operator applied to unsupported type", "Foo^", "Foo^"),
BindingErrorType.Error)
},
result);
sub.Dispose();
}
}
private class Class1 : NotifyingBase
{
public Subject<Class2> Next { get; } = new Subject<Class2>();

4
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Property.cs

@ -146,7 +146,7 @@ namespace Avalonia.Markup.UnitTests.Data
new[]
{
new BindingNotification(
new MarkupBindingChainNullException("Foo.Bar.Baz", "Foo"),
new MarkupBindingChainException("Null value", "Foo.Bar.Baz", "Foo"),
BindingErrorType.Error,
AvaloniaProperty.UnsetValue),
},
@ -274,7 +274,7 @@ namespace Avalonia.Markup.UnitTests.Data
{
"bar",
new BindingNotification(
new MarkupBindingChainNullException("Next.Next.Bar", "Next.Next"),
new MarkupBindingChainException("Null value", "Next.Next.Bar", "Next.Next"),
BindingErrorType.Error,
AvaloniaProperty.UnsetValue),
"bar"

15
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Task.cs

@ -15,7 +15,7 @@ namespace Avalonia.Markup.UnitTests.Data
public class ExpressionObserverTests_Task
{
[Fact]
public void Should_Get_Simple_Task_Value()
public void Should_Not_Get_Task_Result_Without_Modifier_Char()
{
using (var sync = UnitTestSynchronizationContext.Begin())
{
@ -28,7 +28,8 @@ namespace Avalonia.Markup.UnitTests.Data
tcs.SetResult("foo");
sync.ExecutePostedCallbacks();
Assert.Equal(new[] { "foo" }, result);
Assert.Equal(1, result.Count);
Assert.IsType<Task<string>>(result[0]);
}
}
@ -38,7 +39,7 @@ namespace Avalonia.Markup.UnitTests.Data
using (var sync = UnitTestSynchronizationContext.Begin())
{
var data = new { Foo = Task.FromResult("foo") };
var target = new ExpressionObserver(data, "Foo");
var target = new ExpressionObserver(data, "Foo^");
var result = new List<object>();
var sub = target.Subscribe(x => result.Add(x));
@ -54,7 +55,7 @@ namespace Avalonia.Markup.UnitTests.Data
{
var tcs = new TaskCompletionSource<Class2>();
var data = new Class1(tcs.Task);
var target = new ExpressionObserver(data, "Next.Foo");
var target = new ExpressionObserver(data, "Next^.Foo");
var result = new List<object>();
var sub = target.Subscribe(x => result.Add(x));
@ -72,7 +73,7 @@ namespace Avalonia.Markup.UnitTests.Data
{
var tcs = new TaskCompletionSource<string>();
var data = new { Foo = tcs.Task };
var target = new ExpressionObserver(data, "Foo");
var target = new ExpressionObserver(data, "Foo^");
var result = new List<object>();
var sub = target.Subscribe(x => result.Add(x));
@ -96,7 +97,7 @@ namespace Avalonia.Markup.UnitTests.Data
using (var sync = UnitTestSynchronizationContext.Begin())
{
var data = new { Foo = TaskFromException(new NotSupportedException()) };
var target = new ExpressionObserver(data, "Foo");
var target = new ExpressionObserver(data, "Foo^");
var result = new List<object>();
var sub = target.Subscribe(x => result.Add(x));
@ -119,7 +120,7 @@ namespace Avalonia.Markup.UnitTests.Data
{
var tcs = new TaskCompletionSource<string>();
var data = new { Foo = tcs.Task };
var target = new ExpressionObserver(data, "Foo", true);
var target = new ExpressionObserver(data, "Foo^", true);
var result = new List<object>();
var sub = target.Subscribe(x => result.Add(x));

Loading…
Cancel
Save