[UWP] Fix crash on Switch Renderer when a custom renderer provides Color objects...
authorJavier Suárez Ruiz <javiersuarezruiz@hotmail.com>
Wed, 2 Oct 2019 07:53:15 +0000 (09:53 +0200)
committerRui Marinho <me@ruimarinho.net>
Wed, 2 Oct 2019 07:53:14 +0000 (08:53 +0100)
* Fixed 7253 -  UWP Switch custom Renderer using custom colors throws exception

* Fixed merge error in the code

Xamarin.Forms.ControlGallery.WindowsUniversal/CustomSwitchRenderer.cs [new file with mode: 0644]
Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue7253.cs [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
Xamarin.Forms.Platform.UAP/SwitchRenderer.cs

diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/CustomSwitchRenderer.cs b/Xamarin.Forms.ControlGallery.WindowsUniversal/CustomSwitchRenderer.cs
new file mode 100644 (file)
index 0000000..195fd23
--- /dev/null
@@ -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<Switch> 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
index 8af9939..81dc803 100644 (file)
   <ItemGroup>
     <Compile Include="AttachedStateEffectRenderer.cs" />
     <Compile Include="BorderEffect.cs" />
+    <Compile Include="CustomSwitchRenderer.cs" />
     <Compile Include="DisposePageRenderer.cs" />
     <Compile Include="PlatformSpecificCoreGalleryFactory.cs" />
     <Compile Include="RegistrarValidationService.cs" />
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 (file)
index 0000000..ea05cbb
--- /dev/null
@@ -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
index 0cd3eba..9f877f2 100644 (file)
@@ -23,6 +23,7 @@
     <Compile Include="$(MSBuildThisFileDirectory)Issue5354.xaml.cs">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="$(MSBuildThisFileDirectory)Issue7253.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue7621.xaml.cs">
       <SubType>Code</SubType>
     </Compile>
index 297e6a5..cc6dc87 100644 (file)
@@ -131,6 +131,7 @@ namespace Xamarin.Forms.Platform.UWP
                                return;
 
                        var grid = Control.GetFirstDescendant<Windows.UI.Xaml.Controls.Grid>();
+
                        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