public void TestObjectPathExpressionArrayIndexer() { var exp = ObjectPathExpression.Parse("[0]"); var eval = exp.Evaluate(new int[] { 100, 200, 300 }); Assert.AreEqual(100, eval); }
public void TestObjectPathExpressionStringIndexer() { var exp = ObjectPathExpression.Parse("[0]"); var eval = exp.Evaluate("ABCD"); Assert.AreEqual('A', eval); }
public void TestObjectPathExpressionNestedProperty() { var exp = ObjectPathExpression.Parse("Person.FirstName"); var eval = exp.Evaluate(new { Person = new { FirstName = "John", LastName = "Smith" } }); Assert.AreEqual("John", eval); }
public void TestObjectPathExpressionSingleProperty() { var exp = ObjectPathExpression.Parse("Length"); var eval = exp.Evaluate("1234"); Assert.AreEqual(4, eval); }
public void TestOneLevel() { var testString = "Adam"; var expression = ObjectPathExpression.Parse("Length"); var eval = expression.Evaluate(testString); Assert.AreEqual(testString.Length, eval); }
public void TestObjectPathExpressionDictionaryIndexerWithSpaces() { var exp = ObjectPathExpression.Parse("[\"Meaning Of Life\"]"); var eval = exp.Evaluate(new Dictionary <string, int>() { { "Meaning Of Life", 42 } }); Assert.AreEqual(42, eval); }
public void TestObjectPathExpressionNestedPropertyAfterIndexerWithWhitespaceEverywhere() { var exp = ObjectPathExpression.Parse(" [ 0 ] . Person . FirstName "); var eval = exp.Evaluate(new object[] { new { Person = new { FirstName = "John", LastName = "Smith" } }, new { Person = new { FirstName = "Bob", LastName = "Smith" } } }); Assert.AreEqual("John", eval); }
public void TestBackToBackIndexer() { var testObj = new string[1][]; testObj[0] = new string[1]; testObj[0][0] = "Adam"; var expression = ObjectPathExpression.Parse("[0][0]"); var eval = expression.Evaluate(testObj); Assert.AreEqual(testObj[0][0], eval); }
public ViewModelBinding(ConsoleControl control, PropertyInfo controlProperty, ObservableObject viewModel, string observablePath, Func <object, object> mapper, Func <object, object> reverseMapper) { this.mapper = mapper; this.reverseMapper = reverseMapper; var exp = ObjectPathExpression.Parse(observablePath); var trace = exp.EvaluateAndTraceInfo(viewModel); var observableObject = trace[trace.Count - 2].Value as ObservableObject; var viewModelObservableProperty = trace.Last()?.MemberInfo as PropertyInfo; if (observableObject == null) { throw new InvalidOperationException($"ViewModel property '{viewModel.GetType().FullName}.{observablePath}' is not observable"); } if (viewModelObservableProperty == null) { throw new InvalidOperationException($"Cannot resolve ViewModel property '{viewModel.GetType().FullName}.{observablePath}'"); } if (mapper != null && reverseMapper != null) { if (viewModelObservableProperty.PropertyType != controlProperty.PropertyType && viewModelObservableProperty.PropertyType.IsSubclassOf(controlProperty.PropertyType) == false && viewModelObservableProperty.PropertyType.GetInterfaces().Contains(controlProperty.PropertyType) == false) { throw new InvalidOperationException($"ViewModel type '{viewModel.GetType().FullName} property {observablePath}' of type {viewModelObservableProperty.PropertyType.FullName} is not compatible with control property '{controlProperty.DeclaringType.FullName}.{controlProperty.Name}' of type {controlProperty.PropertyType.FullName} "); } } observableObject.SynchronizeForLifetime(trace.Last().MemberInfo.Name, () => { var newValue = viewModelObservableProperty.GetValue(observableObject); if (newValue == latestValue) { return; } latestValue = newValue; controlProperty.SetValue(control, mapper != null ? mapper(newValue) : newValue); }, control.LifetimeManager); control.SubscribeForLifetime(controlProperty.Name, () => { var newValue = controlProperty.GetValue(control); if (newValue == latestValue) { return; } latestValue = newValue; viewModelObservableProperty.SetValue(observableObject, reverseMapper != null ? reverseMapper(newValue) : newValue); }, control.LifetimeManager); }
public void TestTwoLevels() { var testObj = new Customer() { Name = "Adam", Address = new Address() { Line1 = "123 Main Street", Line2 = "Seattle, WA", ZipCode = "12345" } }; var expression = ObjectPathExpression.Parse("Address.Line1"); var eval = expression.Evaluate(testObj); Assert.AreEqual(testObj.Address.Line1, eval); }
public void TestDeep() { var testObj = new Customer() { Name = "Adam", Address = new Address() { Line1 = "123 Main Street", Line2 = "Seattle, WA", ZipCode = "12345" } }; testObj.RelatedCustomers.Add(testObj); var expression = ObjectPathExpression.Parse("RelatedCustomers[0].RelatedCustomers[0].Name"); var eval = expression.Evaluate(testObj); Assert.AreEqual(testObj.RelatedCustomers[0].RelatedCustomers[0].Name, eval); }
private IDisposable DeepSubscribeInternal(string path, Action handler, Lifetime rootLifetime = null) { rootLifetime = rootLifetime ?? new Lifetime(); var observableRoot = DeepObservableRoot ?? this; IObservableObject currentObservable = observableRoot; var pathExpression = ObjectPathExpression.Parse(path); List <IObjectPathElement> currentPath = new List <IObjectPathElement>(); var anyChangeLifetime = new Lifetime(); for (int i = 0; i < pathExpression.Elements.Count; i++) { var propertyElement = pathExpression.Elements[i] as PropertyPathElement; if (propertyElement == null) { throw new NotSupportedException("Indexers are not supported for deep observability"); } currentPath.Add(propertyElement); ObjectPathExpression.TraceNode eval; if (i == pathExpression.Elements.Count - 1 && propertyElement.PropertyName == ObservableObject.AnyProperty) { eval = new ObjectPathExpression.TraceNode() { Value = null }; } else { eval = new ObjectPathExpression(currentPath).EvaluateAndTraceInfo(observableRoot).Last(); if (i != pathExpression.Elements.Count - 1 && (eval.MemberInfo as PropertyInfo).PropertyType.GetInterfaces().Contains(typeof(IObservableObject)) == false) { throw new NotSupportedException($"element {eval.MemberInfo.Name} is not observable"); } } currentObservable.SubscribeForLifetime(propertyElement.PropertyName, () => { handler(); if (anyChangeLifetime.IsExpired == false) { anyChangeLifetime.Dispose(); } if (rootLifetime.IsExpired == false) { DeepSubscribeInternal(path, handler, rootLifetime); } }, EarliestOf(anyChangeLifetime, rootLifetime).LifetimeManager); currentObservable = eval.Value as IObservableObject; if (currentObservable == null) { break; } } return(rootLifetime); }