public void AttachPropertyChangedHandler_Should_Be_Called_On_Chain() { var source = new Mock<IObservableDependencyObject>(); var foo = new Mock<IObservableDependencyObject>(); var bar = new Mock<IObservableDependencyObject>(); Mock<IPropertyPathParser> mockPathParser = new Mock<IPropertyPathParser>(); mockPathParser.Setup(x => x.Parse(source.Object, "Foo.Bar")).Returns(new[] { new PropertyPathToken(source.Object, "Foo"), new PropertyPathToken(foo.Object, "Bar"), new PropertyPathToken(bar.Object, null), }); Mock<DependencyObject> mockTarget = new Mock<DependencyObject>(); Binding binding = new Binding { Path = new PropertyPath("Foo.Bar"), Source = source.Object, }; BindingExpression target = new BindingExpression( mockPathParser.Object, mockTarget.Object, Control.BackgroundProperty, binding); target.GetValue(); source.Verify(x => x.AttachPropertyChangedHandler("Foo", It.IsAny<DependencyPropertyChangedEventHandler>())); foo.Verify(x => x.AttachPropertyChangedHandler("Bar", It.IsAny<DependencyPropertyChangedEventHandler>())); bar.Verify(x => x.AttachPropertyChangedHandler("Bar", It.IsAny<DependencyPropertyChangedEventHandler>()), Times.Never()); }
public async void Getting_Invalid_Double_String_Should_Return_BindingError() { var data = new Class1 { StringValue = "foo" }; var target = new BindingExpression(new ExpressionObserver(data, "StringValue"), typeof(double)); var result = await target.Take(1); Assert.IsType<BindingNotification>(result); }
public async void Should_Get_Simple_Property_Value() { var data = new Class1 { StringValue = "foo" }; var target = new BindingExpression(new ExpressionObserver(data, "StringValue"), typeof(string)); var result = await target.Take(1); Assert.Equal("foo", result); }
public async void Should_Coerce_Get_Null_Double_String_To_UnsetValue() { var data = new Class1 { StringValue = null }; var target = new BindingExpression(new ExpressionObserver(data, "StringValue"), typeof(double)); var result = await target.Take(1); Assert.Equal(AvaloniaProperty.UnsetValue, result); }
public void Should_Set_Simple_Property_Value() { var data = new Class1 { StringValue = "foo" }; var target = new BindingExpression(new ExpressionObserver(data, "StringValue"), typeof(string)); target.OnNext("bar"); Assert.Equal("bar", data.StringValue); }
public async void Should_Convert_Get_String_To_Double() { Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; var data = new Class1 { StringValue = "5.6" }; var target = new BindingExpression(new ExpressionObserver(data, "StringValue"), typeof(double)); var result = await target.Take(1); Assert.Equal(5.6, result); }
public void Should_Convert_Set_String_To_Double() { Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; var data = new Class1 { StringValue = (5.6).ToString() }; var target = new BindingExpression(new ExpressionObserver(data, "StringValue"), typeof(double)); target.OnNext(6.7); Assert.Equal((6.7).ToString(), data.StringValue); }
public void Should_Handle_DataValidation() { var data = new Class1 { DoubleValue = 5.6 }; var converter = new Mock<IValueConverter>(); var target = new BindingExpression(new ExpressionObserver(data, "DoubleValue", true), typeof(string)); var result = new List<object>(); target.Subscribe(x => result.Add(x)); target.OnNext(1.2); target.OnNext("3.4"); target.OnNext("bar"); Assert.Equal( new[] { new BindingNotification("5.6"), new BindingNotification("1.2"), new BindingNotification("3.4"), new BindingNotification( new InvalidCastException("'bar' is not a valid number."), BindingErrorType.Error) }, result); }
public void Should_Pass_ConverterParameter_To_ConvertBack() { var data = new Class1 { DoubleValue = 5.6 }; var converter = new Mock<IValueConverter>(); var target = new BindingExpression( new ExpressionObserver(data, "DoubleValue"), typeof(string), converter.Object, converterParameter: "foo"); target.OnNext("bar"); converter.Verify(x => x.ConvertBack("bar", typeof(double), "foo", CultureInfo.CurrentUICulture)); }
public async void Should_Convert_Get_Double_To_String() { Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; var data = new Class1 { DoubleValue = 5.6 }; var target = new BindingExpression(new ExpressionObserver(data, "DoubleValue"), typeof(string)); var result = await target.Take(1); Assert.Equal((5.6).ToString(), result); }
public void Setting_Invalid_Double_String_Should_Not_Change_Target() { var data = new Class1 { DoubleValue = 5.6 }; var target = new BindingExpression(new ExpressionObserver(data, "DoubleValue"), typeof(string)); target.OnNext("foo"); Assert.Equal(5.6, data.DoubleValue); }
public async void Should_Return_BindingNotification_For_Invalid_FallbackValue_With_Data_Validation() { Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; var data = new Class1 { StringValue = "foo" }; var target = new BindingExpression( new ExpressionObserver(data, "StringValue", true), typeof(int), "bar", DefaultValueConverter.Instance); var result = await target.Take(1); Assert.Equal( new BindingNotification( new AggregateException( new InvalidCastException("Could not convert 'foo' to 'System.Int32'"), new InvalidCastException("Could not convert FallbackValue 'bar' to 'System.Int32'")), BindingErrorType.Error), result); }
public async void Should_Return_BindingNotification_With_FallbackValue_For_NonConvertibe_Target_Value_With_Data_Validation() { Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; var data = new Class1 { StringValue = "foo" }; var target = new BindingExpression( new ExpressionObserver(data, "StringValue", true), typeof(int), 42, DefaultValueConverter.Instance); var result = await target.Take(1); Assert.Equal( new BindingNotification( new InvalidCastException("'foo' is not a valid number."), BindingErrorType.Error, 42), result); }
public BindingExpression SetBinding(DependencyProperty dp, Binding binding) { PropertyPathParser pathParser = new PropertyPathParser(); BindingExpression expression = new BindingExpression(pathParser, this, dp, binding); object oldValue = this.GetValue(dp); object newValue = expression.GetValue(); this.propertyBindings.Add(dp, expression); this.SetValueInternal(dp, oldValue, newValue); return expression; }
/// <inheritdoc/> public InstancedBinding Initiate( IAvaloniaObject target, AvaloniaProperty targetProperty, object anchor = null, bool enableDataValidation = false) { Contract.Requires <ArgumentNullException>(target != null); anchor = anchor ?? DefaultAnchor?.Target; enableDataValidation = enableDataValidation && Priority == BindingPriority.LocalValue; ExpressionObserver observer; var(node, mode) = ExpressionObserverBuilder.Parse(Path, enableDataValidation, TypeResolver); if (ElementName != null) { observer = CreateElementObserver( (target as IStyledElement) ?? (anchor as IStyledElement), ElementName, node); } else if (Source != null) { observer = CreateSourceObserver(Source, node); } else if (RelativeSource == null) { if (mode == SourceMode.Data) { observer = CreateDataContextObserver( target, node, targetProperty == StyledElement.DataContextProperty, anchor); } else { observer = new ExpressionObserver( (target as IStyledElement) ?? (anchor as IStyledElement), node); } } else if (RelativeSource.Mode == RelativeSourceMode.DataContext) { observer = CreateDataContextObserver( target, node, targetProperty == StyledElement.DataContextProperty, anchor); } else if (RelativeSource.Mode == RelativeSourceMode.Self) { observer = CreateSourceObserver(target, node); } else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent) { observer = CreateTemplatedParentObserver( (target as IStyledElement) ?? (anchor as IStyledElement), node); } else if (RelativeSource.Mode == RelativeSourceMode.FindAncestor) { if (RelativeSource.Tree == TreeType.Visual && RelativeSource.AncestorType == null) { throw new InvalidOperationException("AncestorType must be set for RelativeSourceMode.FindAncestor when searching the visual tree."); } observer = CreateFindAncestorObserver( (target as IStyledElement) ?? (anchor as IStyledElement), RelativeSource, node); } else { throw new NotSupportedException(); } var fallback = FallbackValue; // If we're binding to DataContext and our fallback is UnsetValue then override // the fallback value to null, as broken bindings to DataContext must reset the // DataContext in order to not propagate incorrect DataContexts to child controls. // See Avalonia.Markup.UnitTests.Data.DataContext_Binding_Should_Produce_Correct_Results. if (targetProperty == StyledElement.DataContextProperty && fallback == AvaloniaProperty.UnsetValue) { fallback = null; } var subject = new BindingExpression( observer, targetProperty?.PropertyType ?? typeof(object), fallback, Converter ?? DefaultValueConverter.Instance, ConverterParameter, Priority); return(new InstancedBinding(subject, Mode, Priority)); }
/// <inheritdoc/> public InstancedBinding Initiate( IAvaloniaObject target, AvaloniaProperty targetProperty, object anchor = null, bool enableDataValidation = false) { Contract.Requires <ArgumentNullException>(target != null); anchor = anchor ?? DefaultAnchor?.Target; enableDataValidation = enableDataValidation && Priority == BindingPriority.LocalValue; ExpressionObserver observer; INameScope nameScope = null; NameScope?.TryGetTarget(out nameScope); var(node, mode) = ExpressionObserverBuilder.Parse(Path, enableDataValidation, TypeResolver, nameScope); if (ElementName != null) { observer = CreateElementObserver( (target as IStyledElement) ?? (anchor as IStyledElement), ElementName, node); } else if (Source != null) { observer = CreateSourceObserver(Source, node); } else if (RelativeSource == null) { if (mode == SourceMode.Data) { observer = CreateDataContextObserver( target, node, targetProperty == StyledElement.DataContextProperty, anchor); } else { observer = new ExpressionObserver( (target as IStyledElement) ?? (anchor as IStyledElement), node); } } else if (RelativeSource.Mode == RelativeSourceMode.DataContext) { observer = CreateDataContextObserver( target, node, targetProperty == StyledElement.DataContextProperty, anchor); } else if (RelativeSource.Mode == RelativeSourceMode.Self) { observer = CreateSourceObserver( (target as IStyledElement) ?? (anchor as IStyledElement), node); } else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent) { observer = CreateTemplatedParentObserver( (target as IStyledElement) ?? (anchor as IStyledElement), node); } else if (RelativeSource.Mode == RelativeSourceMode.FindAncestor) { if (RelativeSource.Tree == TreeType.Visual && RelativeSource.AncestorType == null) { throw new InvalidOperationException("AncestorType must be set for RelativeSourceMode.FindAncestor when searching the visual tree."); } observer = CreateFindAncestorObserver( (target as IStyledElement) ?? (anchor as IStyledElement), RelativeSource, node); } else { throw new NotSupportedException(); } var fallback = FallbackValue; // If we're binding to DataContext and our fallback is UnsetValue then override // the fallback value to null, as broken bindings to DataContext must reset the // DataContext in order to not propagate incorrect DataContexts to child controls. // See Avalonia.Markup.UnitTests.Data.DataContext_Binding_Should_Produce_Correct_Results. if (targetProperty == StyledElement.DataContextProperty && fallback == AvaloniaProperty.UnsetValue) { fallback = null; } var converter = Converter; var targetType = targetProperty?.PropertyType ?? typeof(object); // We only respect `StringFormat` if the type of the property we're assigning to will // accept a string. Note that this is slightly different to WPF in that WPF only applies // `StringFormat` for target type `string` (not `object`). if (!string.IsNullOrWhiteSpace(StringFormat) && (targetType == typeof(string) || targetType == typeof(object))) { converter = new StringFormatValueConverter(StringFormat, converter); } var subject = new BindingExpression( observer, targetType, fallback, TargetNullValue, converter ?? DefaultValueConverter.Instance, ConverterParameter, Priority); return(new InstancedBinding(subject, Mode, Priority)); }
public void Setting_Invalid_Double_String_Should_Use_FallbackValue() { var data = new Class1 { DoubleValue = 5.6 }; var target = new BindingExpression( new ExpressionObserver(data, "DoubleValue"), typeof(string), "9.8", DefaultValueConverter.Instance); target.OnNext("foo"); Assert.Equal(9.8, data.DoubleValue); }
public void Should_Coerce_Setting_UnsetValue_Double_To_Default_Value() { var data = new Class1 { DoubleValue = 5.6 }; var target = new BindingExpression(new ExpressionObserver(data, "DoubleValue"), typeof(string)); target.OnNext(AvaloniaProperty.UnsetValue); Assert.Equal(0, data.DoubleValue); }
public void Should_Convert_Set_Double_To_String() { Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; var data = new Class1 { DoubleValue = 5.6 }; var target = new BindingExpression(new ExpressionObserver(data, "DoubleValue"), typeof(string)); target.OnNext("6.7"); Assert.Equal(6.7, data.DoubleValue); }
/// <inheritdoc/> public InstancedBinding Initiate( IAvaloniaObject target, AvaloniaProperty targetProperty, object anchor = null, bool enableDataValidation = false) { Contract.Requires<ArgumentNullException>(target != null); var pathInfo = ParsePath(Path); ValidateState(pathInfo); enableDataValidation = enableDataValidation && Priority == BindingPriority.LocalValue; ExpressionObserver observer; if (pathInfo.ElementName != null || ElementName != null) { observer = CreateElementObserver( (target as IControl) ?? (anchor as IControl), pathInfo.ElementName ?? ElementName, pathInfo.Path); } else if (Source != null) { observer = CreateSourceObserver(Source, pathInfo.Path, enableDataValidation); } else if (RelativeSource == null || RelativeSource.Mode == RelativeSourceMode.DataContext) { observer = CreateDataContexObserver( target, pathInfo.Path, targetProperty == Control.DataContextProperty, anchor, enableDataValidation); } else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent) { observer = CreateTemplatedParentObserver(target, pathInfo.Path); } else { throw new NotSupportedException(); } var fallback = FallbackValue; // If we're binding to DataContext and our fallback is UnsetValue then override // the fallback value to null, as broken bindings to DataContext must reset the // DataContext in order to not propagate incorrect DataContexts to child controls. // See Avalonia.Markup.Xaml.UnitTests.Data.DataContext_Binding_Should_Produce_Correct_Results. if (targetProperty == Control.DataContextProperty && fallback == AvaloniaProperty.UnsetValue) { fallback = null; } var subject = new BindingExpression( observer, targetProperty?.PropertyType ?? typeof(object), fallback, Converter ?? DefaultValueConverter.Instance, ConverterParameter, Priority); return new InstancedBinding(subject, Mode, Priority); }