From 02c51722e155cd1fac5ed3dc810f98f426e081eb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Javier=20Su=C3=A1rez=20Ruiz?= Date: Wed, 2 Oct 2019 09:53:15 +0200 Subject: [PATCH] [UWP] Fix crash on Switch Renderer when a custom renderer provides Color objects instead of Brush (#7760) fixes #7253 * Fixed 7253 - UWP Switch custom Renderer using custom colors throws exception * Fixed merge error in the code --- .../CustomSwitchRenderer.cs | 70 ++++++++++++++++++++++ ...in.Forms.ControlGallery.WindowsUniversal.csproj | 1 + .../Issue7253.cs | 60 +++++++++++++++++++ .../Xamarin.Forms.Controls.Issues.Shared.projitems | 1 + Xamarin.Forms.Platform.UAP/SwitchRenderer.cs | 23 ++++--- 5 files changed, 148 insertions(+), 7 deletions(-) create mode 100644 Xamarin.Forms.ControlGallery.WindowsUniversal/CustomSwitchRenderer.cs create mode 100644 Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue7253.cs diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/CustomSwitchRenderer.cs b/Xamarin.Forms.ControlGallery.WindowsUniversal/CustomSwitchRenderer.cs new file mode 100644 index 0000000..195fd23 --- /dev/null +++ b/Xamarin.Forms.ControlGallery.WindowsUniversal/CustomSwitchRenderer.cs @@ -0,0 +1,70 @@ +using System.ComponentModel; +using Xamarin.Forms.ControlGallery.WindowsUniversal; +using Xamarin.Forms.Controls.Issues; +using Xamarin.Forms.Platform.UWP; +using WResourceDictionary = Windows.UI.Xaml.ResourceDictionary; + +[assembly: ExportRenderer(typeof(CustomSwitch), typeof(CustomSwitchRenderer))] +namespace Xamarin.Forms.ControlGallery.WindowsUniversal +{ + // Used in Issue7253.cs + public class CustomSwitchRenderer : SwitchRenderer + { + protected CustomSwitch CustomSwitch => Element as CustomSwitch; + + protected CustomSwitchStyle CustomStyle { get; set; } + + protected override void OnElementChanged(ElementChangedEventArgs e) + { + base.OnElementChanged(e); + + if (e.NewElement == null) + return; + + Control.OnContent = null; + Control.OffContent = null; + CustomStyle = new CustomSwitchStyle(); + Control.Resources = CustomStyle; + + OnElementPropertyChanged(this, new PropertyChangedEventArgs(nameof(CustomSwitch.CustomColor))); + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) + { + switch (e.PropertyName) + { + case nameof(CustomSwitch.CustomColor): + CustomStyle.ToggleSwitchStrokeOn(CustomSwitch.CustomColor.ToUwpColor()); + CustomStyle.ToggleSwitchStrokeOff(CustomSwitch.CustomColor.ToUwpColor()); + CustomStyle.ToggleSwitchKnobFillOn(CustomSwitch.CustomColor.ToUwpColor()); + CustomStyle.ToggleSwitchKnobFillOff(CustomSwitch.CustomColor.ToUwpColor()); + CustomStyle.ToggleSwitchStrokeOnPointerOver(CustomSwitch.CustomColor.ToUwpColor()); + CustomStyle.ToggleSwitchStrokeOffPointerOver(CustomSwitch.CustomColor.ToUwpColor()); + CustomStyle.ToggleSwitchKnobFillOffPointerOver(CustomSwitch.CustomColor.ToUwpColor()); + CustomStyle.ToggleSwitchKnobFillOnPointerOver(CustomSwitch.CustomColor.ToUwpColor()); + break; + } + + base.OnElementPropertyChanged(sender, e); + } + + protected class CustomSwitchStyle : WResourceDictionary + { + public void ToggleSwitchStrokeOn(Windows.UI.Color c) => this["ToggleSwitchStrokeOn"] = c; + public void ToggleSwitchStrokeOff(Windows.UI.Color c) => this["ToggleSwitchStrokeOff"] = c; + public void ToggleSwitchKnobFillOn(Windows.UI.Color c) => this["ToggleSwitchKnobFillOn"] = c; + public void ToggleSwitchKnobFillOff(Windows.UI.Color c) => this["ToggleSwitchKnobFillOff"] = c; + public void ToggleSwitchStrokeOnPointerOver(Windows.UI.Color c) => this["ToggleSwitchStrokeOnPointerOver"] = c; + public void ToggleSwitchStrokeOffPointerOver(Windows.UI.Color c) => this["ToggleSwitchStrokeOffPointerOver"] = c; + public void ToggleSwitchKnobFillOffPointerOver(Windows.UI.Color c) => this["ToggleSwitchKnobFillOffPointerOver"] = c; + public void ToggleSwitchKnobFillOnPointerOver(Windows.UI.Color c) => this["ToggleSwitchKnobFillOnPointerOver"] = c; + + } + } + + public static class ColorHelper + { + public static Windows.UI.Color ToUwpColor(this Color xColor) => + Windows.UI.Color.FromArgb((byte)(xColor.A * 255), (byte)(xColor.R * 255), (byte)(xColor.G * 255), (byte)(xColor.B * 255)); + } +} \ No newline at end of file diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj b/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj index 8af9939..81dc803 100644 --- a/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj +++ b/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj @@ -121,6 +121,7 @@ + diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue7253.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue7253.cs new file mode 100644 index 0000000..ea05cbb --- /dev/null +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue7253.cs @@ -0,0 +1,60 @@ +using Xamarin.Forms.Internals; +using Xamarin.Forms.CustomAttributes; + +#if UITEST +using Xamarin.UITest; +using NUnit.Framework; +using Xamarin.Forms.Core.UITests; +#endif + +namespace Xamarin.Forms.Controls.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 7253, "[UWP] Switch custom Renderer using custom colors throws exception", PlatformAffected.UWP)] +#if UITEST + [Category(UITestCategories.ManualReview)] +#endif + public class Issue7253 : TestContentPage + { + public Issue7253() + { + Title = "Issue 7253"; + } + + protected override void Init() + { + var layout = new StackLayout + { + Padding = new Thickness(12) + }; + + var instructions = new Label + { + Text = "If the custom Switch below is rendering without problems, the test passes." + }; + + var customSwitch = new CustomSwitch + { + CustomColor = Color.Red + }; + + layout.Children.Add(instructions); + layout.Children.Add(customSwitch); + + Content = layout; + } + } + + [Preserve(AllMembers = true)] + public class CustomSwitch : Switch + { + public static readonly BindableProperty CustomColorProperty = + BindableProperty.Create(nameof(CustomColor), typeof(Color), typeof(CustomSwitch), Color.Black); + + public Color CustomColor + { + get => (Color)GetValue(CustomColorProperty); + set => SetValue(CustomColorProperty, value); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems index 0cd3eba..9f877f2 100644 --- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems @@ -23,6 +23,7 @@ Code + Code diff --git a/Xamarin.Forms.Platform.UAP/SwitchRenderer.cs b/Xamarin.Forms.Platform.UAP/SwitchRenderer.cs index 297e6a5..cc6dc87 100644 --- a/Xamarin.Forms.Platform.UAP/SwitchRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/SwitchRenderer.cs @@ -131,6 +131,7 @@ namespace Xamarin.Forms.Platform.UWP return; var grid = Control.GetFirstDescendant(); + if (grid == null) return; @@ -143,24 +144,32 @@ namespace Xamarin.Forms.Platform.UWP .KeyFrames.First(); if (_originalThumbOnBrush == null) - _originalThumbOnBrush = (Brush)frame.Value; + { + if (frame.Value is Windows.UI.Color color) + _originalOnColorBrush = new SolidColorBrush(color); + + if (frame.Value is Brush brush) + _originalThumbOnBrush = brush; + } if (!Element.ThumbColor.IsDefault) - frame.Value = new SolidColorBrush(Element.ThumbColor.ToWindowsColor()) - { - Opacity = _originalThumbOnBrush.Opacity - }; + { + var brush = Element.ThumbColor.ToBrush(); + brush.Opacity = _originalThumbOnBrush.Opacity; + frame.Value = brush; + } else frame.Value = _originalThumbOnBrush; var thumb = (Ellipse)grid.FindName("SwitchKnobOn"); + if (_originalThumbOnBrush == null) _originalThumbOnBrush = thumb.Fill; if (!Element.ThumbColor.IsDefault) - thumb.Fill = new SolidColorBrush(Element.ThumbColor.ToWindowsColor()); + thumb.Fill = Element.ThumbColor.ToBrush(); else thumb.Fill = _originalThumbOnBrush; } } -} +} \ No newline at end of file -- 2.7.4