Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit c1d1d52

Browse files
authored
[Core] Notify changes in a GradientStop (Color, Offset) (#11783) fixes #11898
* Added repro sample * Updated sample * Fix the issue
1 parent 027afa9 commit c1d1d52

File tree

5 files changed

+192
-8
lines changed

5 files changed

+192
-8
lines changed

Xamarin.Forms.Controls/GalleryPages/GradientGalleries/GradientsGallery.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public GradientsGallery()
5858
new RadialGradientExplorerGallery(), Navigation),
5959
GalleryBuilder.NavButton("Bindable Brush Gallery", () =>
6060
new BindableBrushGallery(), Navigation),
61+
GalleryBuilder.NavButton("Update Brush Colors Gallery", () =>
62+
new UpdateGradientColorGallery(), Navigation),
6163
GalleryBuilder.NavButton("Animate Brush Gallery", () =>
6264
new AnimateBrushGallery(), Navigation),
6365
navigationBarButton,
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ContentPage
3+
xmlns="http://xamarin.com/schemas/2014/forms"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
5+
x:Class="Xamarin.Forms.Controls.GalleryPages.GradientGalleries.UpdateGradientColorGallery"
6+
Title="Update Gradient Color Gallery">
7+
<ContentPage.Content>
8+
<StackLayout
9+
Padding="12">
10+
<Label
11+
Text="SolidColorBrush"/>
12+
<Frame
13+
BorderColor="LightGray"
14+
HasShadow="True"
15+
CornerRadius="12"
16+
HeightRequest="120"
17+
WidthRequest="120">
18+
<Frame.Background>
19+
<SolidColorBrush x:Name="SolidBrush" Color="Red" />
20+
</Frame.Background>
21+
</Frame>
22+
<Button
23+
Text="Update Color"
24+
Clicked="OnUpdateSolidColorClicked"/>
25+
<Label
26+
Text="LinearGradientBrush"/>
27+
<Frame
28+
BorderColor="LightGray"
29+
HasShadow="True"
30+
CornerRadius="12"
31+
HeightRequest="120"
32+
WidthRequest="120">
33+
<Frame.Background>
34+
<LinearGradientBrush x:Name="LinearBrush" StartPoint="0,1" EndPoint="0,0">
35+
<GradientStop Color="Blue" Offset="0.3"/>
36+
<GradientStop Color="Purple" Offset="0.6"/>
37+
<GradientStop Color="Green" Offset="0.9"/>
38+
</LinearGradientBrush>
39+
</Frame.Background>
40+
</Frame>
41+
<Button
42+
Text="Update Colors"
43+
Clicked="OnUpdateLinearColorsClicked"/>
44+
<Label
45+
Text="RadialGradientBrush"/>
46+
<Frame
47+
BorderColor="LightGray"
48+
HasShadow="True"
49+
CornerRadius="12"
50+
HeightRequest="120"
51+
WidthRequest="120">
52+
<Frame.Background>
53+
<RadialGradientBrush x:Name="RadialBrush" Center="0.5, 0.5" Radius="60">
54+
<GradientStop Color="Blue" Offset="0.3"/>
55+
<GradientStop Color="Purple" Offset="0.6"/>
56+
<GradientStop Color="Green" Offset="0.9"/>
57+
</RadialGradientBrush>
58+
</Frame.Background>
59+
</Frame>
60+
<Button
61+
Text="Update Colors"
62+
Clicked="OnUpdateRadialColorsClicked"/>
63+
</StackLayout>
64+
</ContentPage.Content>
65+
</ContentPage>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
3+
namespace Xamarin.Forms.Controls.GalleryPages.GradientGalleries
4+
{
5+
public partial class UpdateGradientColorGallery : ContentPage
6+
{
7+
readonly Random _random;
8+
9+
public UpdateGradientColorGallery()
10+
{
11+
InitializeComponent();
12+
_random = new Random();
13+
}
14+
15+
void OnUpdateSolidColorClicked(object sender, EventArgs e)
16+
{
17+
SolidBrush.Color = GetRandomColor();
18+
}
19+
20+
void OnUpdateLinearColorsClicked(object sender, EventArgs e)
21+
{
22+
GradientStop randomStop = LinearBrush.GradientStops[GetRandomGradientStop()];
23+
randomStop.Color = GetRandomColor();
24+
}
25+
26+
void OnUpdateRadialColorsClicked(object sender, EventArgs e)
27+
{
28+
GradientStop firstStop = RadialBrush.GradientStops[GetRandomGradientStop()];
29+
firstStop.Color = GetRandomColor();
30+
}
31+
32+
int GetRandomGradientStop()
33+
{
34+
return _random.Next(3);
35+
}
36+
37+
Color GetRandomColor()
38+
{
39+
return Color.FromRgb(_random.Next(256), _random.Next(256), _random.Next(256));
40+
}
41+
}
42+
}

Xamarin.Forms.Core/GradientBrush.cs

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using System.Runtime.CompilerServices;
1+
using System;
2+
using System.Collections.Specialized;
3+
using System.ComponentModel;
4+
using System.Runtime.CompilerServices;
25

36
namespace Xamarin.Forms
47
{
@@ -14,6 +17,8 @@ public GradientBrush()
1417
GradientStops = new GradientStopCollection();
1518
}
1619

20+
public event EventHandler InvalidateGradientBrushRequested;
21+
1722
internal static void VerifyExperimental([CallerMemberName] string memberName = "", string constructorHint = null)
1823
{
1924
if (IsExperimentalFlagSet)
@@ -24,13 +29,79 @@ internal static void VerifyExperimental([CallerMemberName] string memberName = "
2429
IsExperimentalFlagSet = true;
2530
}
2631

27-
public static readonly BindableProperty GradientStopsProperty = BindableProperty.Create(
28-
nameof(GradientStops), typeof(GradientStopCollection), typeof(GradientBrush), null);
32+
public static readonly BindableProperty GradientStopsProperty =
33+
BindableProperty.Create(nameof(GradientStops), typeof(GradientStopCollection), typeof(GradientBrush), null,
34+
propertyChanged: OnGradientStopsChanged);
2935

3036
public GradientStopCollection GradientStops
3137
{
3238
get => (GradientStopCollection)GetValue(GradientStopsProperty);
3339
set => SetValue(GradientStopsProperty, value);
3440
}
41+
42+
static void OnGradientStopsChanged(BindableObject bindable, object oldValue, object newValue)
43+
{
44+
(bindable as GradientBrush)?.UpdateGradientStops(oldValue as GradientStopCollection, newValue as GradientStopCollection);
45+
}
46+
47+
void UpdateGradientStops(GradientStopCollection oldCollection, GradientStopCollection newCollection)
48+
{
49+
if (oldCollection != null)
50+
{
51+
oldCollection.CollectionChanged -= OnGradientStopCollectionChanged;
52+
53+
foreach (var oldStop in oldCollection)
54+
{
55+
oldStop.PropertyChanged -= OnGradientStopPropertyChanged;
56+
}
57+
}
58+
59+
if (newCollection == null)
60+
return;
61+
62+
newCollection.CollectionChanged += OnGradientStopCollectionChanged;
63+
64+
foreach (var newStop in newCollection)
65+
{
66+
newStop.PropertyChanged += OnGradientStopPropertyChanged;
67+
}
68+
}
69+
70+
void OnGradientStopCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
71+
{
72+
if (e.OldItems != null)
73+
{
74+
foreach (var oldItem in e.OldItems)
75+
{
76+
if (!(oldItem is GradientStop oldStop))
77+
continue;
78+
79+
oldStop.PropertyChanged -= OnGradientStopPropertyChanged;
80+
}
81+
}
82+
83+
if (e.NewItems != null)
84+
{
85+
foreach (var newItem in e.NewItems)
86+
{
87+
if (!(newItem is GradientStop newStop))
88+
continue;
89+
90+
newStop.PropertyChanged += OnGradientStopPropertyChanged;
91+
}
92+
}
93+
94+
Invalidate();
95+
}
96+
97+
void OnGradientStopPropertyChanged(object sender, PropertyChangedEventArgs e)
98+
{
99+
Invalidate();
100+
}
101+
102+
void Invalidate()
103+
{
104+
InvalidateGradientBrushRequested?.Invoke(this, EventArgs.Empty);
105+
}
35106
}
36107
}

Xamarin.Forms.Core/VisualElement.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,10 @@ void NotifyBackgroundChanges()
168168
{
169169
if (Background != null)
170170
{
171-
Background.PropertyChanging += OnBackgroundChanging;
172171
Background.PropertyChanged += OnBackgroundChanged;
172+
173+
if (Background is GradientBrush gradientBrush)
174+
gradientBrush.InvalidateGradientBrushRequested += InvalidateGradientBrushRequested;
173175
}
174176
}
175177

@@ -178,16 +180,18 @@ void StopNotifyingBackgroundChanges()
178180
if (Background != null)
179181
{
180182
Background.PropertyChanged -= OnBackgroundChanged;
181-
Background.PropertyChanging -= OnBackgroundChanging;
183+
184+
if (Background is GradientBrush gradientBrush)
185+
gradientBrush.InvalidateGradientBrushRequested -= InvalidateGradientBrushRequested;
182186
}
183187
}
184188

185-
void OnBackgroundChanging(object sender, PropertyChangingEventArgs e)
189+
void OnBackgroundChanged(object sender, PropertyChangedEventArgs e)
186190
{
187-
OnPropertyChanging(nameof(Background));
191+
OnPropertyChanged(nameof(Background));
188192
}
189193

190-
void OnBackgroundChanged(object sender, PropertyChangedEventArgs e)
194+
void InvalidateGradientBrushRequested(object sender, EventArgs e)
191195
{
192196
OnPropertyChanged(nameof(Background));
193197
}

0 commit comments

Comments
 (0)