Ejemplo n.º 1
0
        /// <inheritdoc/>
        public InstancedBinding Initiate(
            IAvaloniaObject target,
            AvaloniaProperty targetProperty,
            object?anchor             = null,
            bool enableDataValidation = false)
        {
            _ = target ?? throw new ArgumentNullException(nameof(target));

            anchor = anchor ?? DefaultAnchor?.Target;

            enableDataValidation = enableDataValidation && Priority == BindingPriority.LocalValue;

            var observer = CreateExpressionObserver(target, targetProperty, anchor, enableDataValidation);

            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));
        }
Ejemplo n.º 2
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 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,
                converter ?? DefaultValueConverter.Instance,
                ConverterParameter,
                Priority);

            return(new InstancedBinding(subject, Mode, Priority));
        }