/// <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)); }
/// <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)); }