From 2d17f170af3c83354cb8990977b9b0970ce4abc2 Mon Sep 17 00:00:00 2001 From: NirmalKumarYuvaraj <97871636+NirmalKumarYuvaraj@users.noreply.github.com> Date: Mon, 21 Jul 2025 14:08:00 +0530 Subject: [PATCH 1/4] added FIll to boxview --- src/Controls/src/Core/BoxView/BoxView.cs | 65 ++++- .../src/Core/Internals/WeakEventProxy.cs | 44 +++ src/Controls/src/Core/Shapes/Shape.cs | 44 --- .../BoxView/BoxViewControlPage.xaml | 64 +++-- .../FeatureMatrix/BoxView/BoxViewViewModel.cs | 128 ++++++++- .../FeatureMatrix/BoxViewFeatureTests.cs | 268 ++++++++++-------- .../ios/BoxView_ColorWithOpacity.png | Bin 78966 -> 86335 bytes .../ios/BoxView_ColorWithOpacityAndShadow.png | Bin 84580 -> 91981 bytes .../ios/BoxView_CornerRadiusWithColor.png | Bin 86630 -> 93680 bytes ...BoxView_CornerRadiusWithColorAndShadow.png | Bin 97636 -> 104235 bytes .../BoxView_CornerRadiusWithFlowDirection.png | Bin 86523 -> 93532 bytes ...xView_CornerRadiusWithOpacityAndShadow.png | Bin 94663 -> 101322 bytes .../ios/BoxView_FillWithLinearGradient.png | Bin 0 -> 167185 bytes .../ios/BoxView_FillWithRadialGradient.png | Bin 0 -> 171441 bytes .../ios/BoxView_FillWithSolidColor.png | Bin 0 -> 101936 bytes .../snapshots/ios/BoxView_IsVisible.png | Bin 83663 -> 90886 bytes 16 files changed, 419 insertions(+), 194 deletions(-) create mode 100644 src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/BoxView_FillWithLinearGradient.png create mode 100644 src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/BoxView_FillWithRadialGradient.png create mode 100644 src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/BoxView_FillWithSolidColor.png diff --git a/src/Controls/src/Core/BoxView/BoxView.cs b/src/Controls/src/Core/BoxView/BoxView.cs index fdb7a9000bfd..1eccf94448fc 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; /// @@ -60,6 +80,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 +130,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/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.HostApp/FeatureMatrix/BoxView/BoxViewControlPage.xaml b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/BoxView/BoxViewControlPage.xaml index 7bd084b2ae43..efa44233a4cb 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 @@ -