diff --git a/src/Controls/src/Core/BoxView/BoxView.cs b/src/Controls/src/Core/BoxView/BoxView.cs index fdb7a9000bfd..ed921f0074a0 100644 --- a/src/Controls/src/Core/BoxView/BoxView.cs +++ b/src/Controls/src/Core/BoxView/BoxView.cs @@ -1,6 +1,5 @@ #nullable disable using System; -using System.ComponentModel; using System.Runtime.CompilerServices; using Microsoft.Maui.Graphics; @@ -11,12 +10,33 @@ namespace Microsoft.Maui.Controls /// public partial class BoxView : View, IColorElement, ICornerElement, IElementConfiguration, IShapeView, IShape { + WeakBrushChangedProxy _fillProxy = null; + EventHandler _fillChanged; + /// Bindable property for . public static readonly BindableProperty ColorProperty = ColorElement.ColorProperty; /// Bindable property for . public static readonly BindableProperty CornerRadiusProperty = CornerElement.CornerRadiusProperty; + /// Bindable property for . + public static readonly BindableProperty FillProperty = + BindableProperty.Create(nameof(Fill), typeof(Brush), typeof(BoxView), null, + propertyChanging: (bindable, oldvalue, newvalue) => + { + if (oldvalue != null) + { + (bindable as BoxView)?.StopNotifyingFillChanges(); + } + }, + propertyChanged: (bindable, oldvalue, newvalue) => + { + if (newvalue != null) + { + (bindable as BoxView)?.NotifyFillChanges(); + } + }); + readonly Lazy> _platformConfigurationRegistry; /// @@ -27,6 +47,11 @@ public BoxView() _platformConfigurationRegistry = new Lazy>(() => new PlatformConfigurationRegistry(this)); } + ~BoxView() + { + _fillProxy?.Unsubscribe(); + } + /// /// Gets or sets the color which will fill the rectangle. This is a bindable property. /// @@ -37,6 +62,19 @@ public Color Color set => SetValue(ColorElement.ColorProperty, value); } + /// + /// Gets or sets the brush that fills the interior of the BoxView. + /// + /// + /// A object that describes how the BoxView's interior is painted. + /// The default value is . + /// + public Brush Fill + { + get => (Brush)GetValue(FillProperty); + set => SetValue(FillProperty, value); + } + /// /// Gets or sets the corner radius for the box view. /// @@ -60,6 +98,45 @@ protected override SizeRequest OnMeasure(double widthConstraint, double heightCo return new SizeRequest(new Size(40, 40)); } + void NotifyFillChanges() + { + var fill = Fill; + + if (fill is ImmutableBrush) + { + return; + } + + if (fill is not null) + { + SetInheritedBindingContext(fill, BindingContext); + _fillChanged ??= (sender, e) => OnPropertyChanged(nameof(Fill)); + _fillProxy ??= new(); + _fillProxy.Subscribe(fill, _fillChanged); + + OnParentResourcesChanged(this.GetMergedResources()); + ((IElementDefinition)this).AddResourcesChangedListener(fill.OnParentResourcesChanged); + } + } + + void StopNotifyingFillChanges() + { + var fill = Fill; + + if (fill is ImmutableBrush) + { + return; + } + + if (fill is not null) + { + ((IElementDefinition)this).RemoveResourcesChangedListener(fill.OnParentResourcesChanged); + + SetInheritedBindingContext(fill, null); + _fillProxy?.Unsubscribe(); + } + } + #nullable enable // Todo these shuold be moved to a mapper protected override void OnPropertyChanged([CallerMemberName] string? propertyName = null) @@ -71,14 +148,16 @@ protected override void OnPropertyChanged([CallerMemberName] string? propertyNam propertyName == IsVisibleProperty.PropertyName || propertyName == BackgroundProperty.PropertyName || propertyName == CornerRadiusProperty.PropertyName) + { Handler?.UpdateValue(nameof(IShapeView.Shape)); + } } IShape? IShapeView.Shape => this; PathAspect IShapeView.Aspect => PathAspect.None; - Paint? IShapeView.Fill => Color?.AsPaint(); + Paint? IShapeView.Fill => Fill ?? Color?.AsPaint(); Paint? IStroke.Stroke => null; diff --git a/src/Controls/src/Core/Internals/WeakEventProxy.cs b/src/Controls/src/Core/Internals/WeakEventProxy.cs index 6f0f1b0af82d..db660c92350e 100644 --- a/src/Controls/src/Core/Internals/WeakEventProxy.cs +++ b/src/Controls/src/Core/Internals/WeakEventProxy.cs @@ -152,4 +152,48 @@ public override void Unsubscribe() base.Unsubscribe(); } } + + class WeakBrushChangedProxy : WeakEventProxy + { + void OnBrushChanged(object? sender, EventArgs e) + { + if (TryGetHandler(out var handler)) + { + handler(sender, e); + } + else + { + Unsubscribe(); + } + } + + public override void Subscribe(Brush source, EventHandler handler) + { + if (TryGetSource(out var s)) + { + s.PropertyChanged -= OnBrushChanged; + + if (s is GradientBrush g) + g.InvalidateGradientBrushRequested -= OnBrushChanged; + } + + source.PropertyChanged += OnBrushChanged; + if (source is GradientBrush gradientBrush) + gradientBrush.InvalidateGradientBrushRequested += OnBrushChanged; + + base.Subscribe(source, handler); + } + + public override void Unsubscribe() + { + if (TryGetSource(out var s)) + { + s.PropertyChanged -= OnBrushChanged; + + if (s is GradientBrush g) + g.InvalidateGradientBrushRequested -= OnBrushChanged; + } + base.Unsubscribe(); + } + } } diff --git a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt index 32a21e9da66a..6b537af9825c 100644 --- a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt @@ -530,3 +530,7 @@ virtual Microsoft.Maui.Controls.Handlers.TabbedPageManager.UpdateTabIcons() -> v ~virtual Microsoft.Maui.Controls.Internals.EvaluateJavaScriptDelegate.Invoke(string script) -> System.Threading.Tasks.Task ~virtual Microsoft.Maui.Controls.PropertyChangingEventHandler.Invoke(object sender, Microsoft.Maui.Controls.PropertyChangingEventArgs e) -> void ~virtual Microsoft.Maui.Controls.VisualElement.ComputeConstraintForView(Microsoft.Maui.Controls.View view) -> Microsoft.Maui.Controls.LayoutConstraint +Microsoft.Maui.Controls.BoxView.~BoxView() -> void +~Microsoft.Maui.Controls.BoxView.Fill.get -> Microsoft.Maui.Controls.Brush +~Microsoft.Maui.Controls.BoxView.Fill.set -> void +~static readonly Microsoft.Maui.Controls.BoxView.FillProperty -> Microsoft.Maui.Controls.BindableProperty diff --git a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt index 869def3ea434..9f7fd1ef8b5b 100644 --- a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt @@ -498,3 +498,7 @@ virtual Microsoft.Maui.Controls.Platform.Compatibility.ShellPageRendererTracker. ~virtual Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRenderer.GetSecondaryToolbarMenuButtonImage() -> UIKit.UIImage ~virtual Microsoft.Maui.Controls.PropertyChangingEventHandler.Invoke(object sender, Microsoft.Maui.Controls.PropertyChangingEventArgs e) -> void ~virtual Microsoft.Maui.Controls.VisualElement.ComputeConstraintForView(Microsoft.Maui.Controls.View view) -> Microsoft.Maui.Controls.LayoutConstraint +Microsoft.Maui.Controls.BoxView.~BoxView() -> void +~Microsoft.Maui.Controls.BoxView.Fill.get -> Microsoft.Maui.Controls.Brush +~Microsoft.Maui.Controls.BoxView.Fill.set -> void +~static readonly Microsoft.Maui.Controls.BoxView.FillProperty -> Microsoft.Maui.Controls.BindableProperty diff --git a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt index 869def3ea434..9f7fd1ef8b5b 100644 --- a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt @@ -498,3 +498,7 @@ virtual Microsoft.Maui.Controls.Platform.Compatibility.ShellPageRendererTracker. ~virtual Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRenderer.GetSecondaryToolbarMenuButtonImage() -> UIKit.UIImage ~virtual Microsoft.Maui.Controls.PropertyChangingEventHandler.Invoke(object sender, Microsoft.Maui.Controls.PropertyChangingEventArgs e) -> void ~virtual Microsoft.Maui.Controls.VisualElement.ComputeConstraintForView(Microsoft.Maui.Controls.View view) -> Microsoft.Maui.Controls.LayoutConstraint +Microsoft.Maui.Controls.BoxView.~BoxView() -> void +~Microsoft.Maui.Controls.BoxView.Fill.get -> Microsoft.Maui.Controls.Brush +~Microsoft.Maui.Controls.BoxView.Fill.set -> void +~static readonly Microsoft.Maui.Controls.BoxView.FillProperty -> Microsoft.Maui.Controls.BindableProperty diff --git a/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt index 239b55f31a2b..d034b8208385 100644 --- a/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt @@ -298,4 +298,8 @@ override Microsoft.Maui.Controls.WebViewSourceTypeConverter.ConvertTo(System.Com Microsoft.Maui.Controls.Xaml.IXamlDataTypeProvider Microsoft.Maui.Controls.Xaml.IXamlDataTypeProvider.BindingDataType.get -> string! ~Microsoft.Maui.Controls.Binding.DataType.get -> System.Type -~Microsoft.Maui.Controls.Binding.DataType.set -> void \ No newline at end of file +~Microsoft.Maui.Controls.Binding.DataType.set -> void +Microsoft.Maui.Controls.BoxView.~BoxView() -> void +~Microsoft.Maui.Controls.BoxView.Fill.get -> Microsoft.Maui.Controls.Brush +~Microsoft.Maui.Controls.BoxView.Fill.set -> void +~static readonly Microsoft.Maui.Controls.BoxView.FillProperty -> Microsoft.Maui.Controls.BindableProperty diff --git a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt index b2acc61e5c3f..7e1babf30165 100644 --- a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt @@ -501,3 +501,7 @@ virtual Microsoft.Maui.Controls.BindableProperty.CreateDefaultValueDelegate System.Threading.Tasks.Task ~virtual Microsoft.Maui.Controls.PropertyChangingEventHandler.Invoke(object sender, Microsoft.Maui.Controls.PropertyChangingEventArgs e) -> void ~virtual Microsoft.Maui.Controls.VisualElement.ComputeConstraintForView(Microsoft.Maui.Controls.View view) -> Microsoft.Maui.Controls.LayoutConstraint +Microsoft.Maui.Controls.BoxView.~BoxView() -> void +~Microsoft.Maui.Controls.BoxView.Fill.get -> Microsoft.Maui.Controls.Brush +~Microsoft.Maui.Controls.BoxView.Fill.set -> void +~static readonly Microsoft.Maui.Controls.BoxView.FillProperty -> Microsoft.Maui.Controls.BindableProperty diff --git a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt index 83dab46327ec..185f075e847e 100644 --- a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt @@ -472,3 +472,7 @@ virtual Microsoft.Maui.Controls.BindableProperty.CreateDefaultValueDelegate System.Threading.Tasks.Task ~virtual Microsoft.Maui.Controls.PropertyChangingEventHandler.Invoke(object sender, Microsoft.Maui.Controls.PropertyChangingEventArgs e) -> void ~virtual Microsoft.Maui.Controls.VisualElement.ComputeConstraintForView(Microsoft.Maui.Controls.View view) -> Microsoft.Maui.Controls.LayoutConstraint +Microsoft.Maui.Controls.BoxView.~BoxView() -> void +~Microsoft.Maui.Controls.BoxView.Fill.get -> Microsoft.Maui.Controls.Brush +~Microsoft.Maui.Controls.BoxView.Fill.set -> void +~static readonly Microsoft.Maui.Controls.BoxView.FillProperty -> Microsoft.Maui.Controls.BindableProperty diff --git a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt index 1b1d6e3c4a4a..a37c85649165 100644 --- a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt @@ -472,3 +472,7 @@ virtual Microsoft.Maui.Controls.BindableProperty.CreateDefaultValueDelegate System.Threading.Tasks.Task ~virtual Microsoft.Maui.Controls.PropertyChangingEventHandler.Invoke(object sender, Microsoft.Maui.Controls.PropertyChangingEventArgs e) -> void ~virtual Microsoft.Maui.Controls.VisualElement.ComputeConstraintForView(Microsoft.Maui.Controls.View view) -> Microsoft.Maui.Controls.LayoutConstraint +Microsoft.Maui.Controls.BoxView.~BoxView() -> void +~Microsoft.Maui.Controls.BoxView.Fill.get -> Microsoft.Maui.Controls.Brush +~Microsoft.Maui.Controls.BoxView.Fill.set -> void +~static readonly Microsoft.Maui.Controls.BoxView.FillProperty -> Microsoft.Maui.Controls.BindableProperty diff --git a/src/Controls/src/Core/Shapes/Shape.cs b/src/Controls/src/Core/Shapes/Shape.cs index 5884f5e9e20a..7e548ecd9fd0 100644 --- a/src/Controls/src/Core/Shapes/Shape.cs +++ b/src/Controls/src/Core/Shapes/Shape.cs @@ -466,49 +466,5 @@ internal virtual double HeightForPathComputation return height == -1 ? _fallbackHeight : height; } } - - class WeakBrushChangedProxy : WeakEventProxy - { - void OnBrushChanged(object? sender, EventArgs e) - { - if (TryGetHandler(out var handler)) - { - handler(sender, e); - } - else - { - Unsubscribe(); - } - } - - public override void Subscribe(Brush source, EventHandler handler) - { - if (TryGetSource(out var s)) - { - s.PropertyChanged -= OnBrushChanged; - - if (s is GradientBrush g) - g.InvalidateGradientBrushRequested -= OnBrushChanged; - } - - source.PropertyChanged += OnBrushChanged; - if (source is GradientBrush gradientBrush) - gradientBrush.InvalidateGradientBrushRequested += OnBrushChanged; - - base.Subscribe(source, handler); - } - - public override void Unsubscribe() - { - if (TryGetSource(out var s)) - { - s.PropertyChanged -= OnBrushChanged; - - if (s is GradientBrush g) - g.InvalidateGradientBrushRequested -= OnBrushChanged; - } - base.Unsubscribe(); - } - } } } \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_ColorWithOpacity.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_ColorWithOpacity.png index afd69b8a07e9..de5850e0a2ea 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_ColorWithOpacity.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_ColorWithOpacity.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_ColorWithOpacityAndShadow.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_ColorWithOpacityAndShadow.png index e7db92a0da75..9c95e8eb14b1 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_ColorWithOpacityAndShadow.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_ColorWithOpacityAndShadow.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithColor.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithColor.png index 4918974d1f34..e2b735e61e9e 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithColor.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithColor.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithColorAndShadow.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithColorAndShadow.png index 279c5c0595c1..d8765b20fd04 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithColorAndShadow.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithColorAndShadow.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithFlowDirection.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithFlowDirection.png index 48652089aa14..61904025abf7 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithFlowDirection.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithFlowDirection.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithOpacityAndShadow.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithOpacityAndShadow.png index c71245ed83ab..0eb5733990e2 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithOpacityAndShadow.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_CornerRadiusWithOpacityAndShadow.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_FillWithLinearGradient.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_FillWithLinearGradient.png new file mode 100644 index 000000000000..7ce642d51e30 Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_FillWithLinearGradient.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_FillWithRadialGradient.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_FillWithRadialGradient.png new file mode 100644 index 000000000000..bf4cb5cdd7be Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_FillWithRadialGradient.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_FillWithSolidColor.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_FillWithSolidColor.png new file mode 100644 index 000000000000..aa2ace9b9b7f Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_FillWithSolidColor.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_IsVisible.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_IsVisible.png index fa4378209b54..33b1b43b362d 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_IsVisible.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BoxView_IsVisible.png differ diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/BoxView/BoxViewControlPage.xaml b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/BoxView/BoxViewControlPage.xaml index 7bd084b2ae43..c900321af1ec 100644 --- a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/BoxView/BoxViewControlPage.xaml +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/BoxView/BoxViewControlPage.xaml @@ -15,6 +15,7 @@