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;
        }
Beispiel #15
0
        /// <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));
        }
Beispiel #16
0
        /// <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);
        }
Beispiel #20
0
        /// <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);
        }