using System.ComponentModel; using System.Linq; using global::Windows.UI.Xaml; using global::Windows.UI.Xaml.Controls; using global::Windows.UI.Xaml.Media; using global::Windows.UI.Xaml.Media.Animation; using global::Windows.UI.Xaml.Shapes; using WColor = global::Windows.UI.Color; using WGrid = global::Windows.UI.Xaml.Controls.Grid; using WRectangle = global::Windows.UI.Xaml.Shapes.Rectangle; using WVisualStateManager = global::Windows.UI.Xaml.VisualStateManager; namespace System.Maui.Platform.UWP { public class SwitchRenderer : ViewRenderer { const string ToggleSwitchCommonStates = "CommonStates"; const string ToggleSwitchPointerOver = "PointerOver"; const string ToggleSwitchKnobBounds = "SwitchKnobBounds"; const string ToggleSwitchKnobOn = "SwitchKnobOn"; const string ToggleSwitchFillMode = "Fill"; object _originalOnHoverColor; Brush _originalOnColorBrush; Brush _originalThumbOnBrush; protected override void OnElementChanged(ElementChangedEventArgs e) { base.OnElementChanged(e); if (e.NewElement != null) { if (Control == null) { var control = new ToggleSwitch(); control.Toggled += OnNativeToggled; control.Loaded += OnControlLoaded; control.ClearValue(ToggleSwitch.OnContentProperty); control.ClearValue(ToggleSwitch.OffContentProperty); SetNativeControl(control); } Control.IsOn = Element.IsToggled; UpdateFlowDirection(); } } protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == Switch.IsToggledProperty.PropertyName) { Control.IsOn = Element.IsToggled; } else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName) { UpdateFlowDirection(); } else if (e.PropertyName == Switch.OnColorProperty.PropertyName) UpdateOnColor(); else if (e.PropertyName == Switch.ThumbColorProperty.PropertyName) UpdateThumbColor(); } protected override bool PreventGestureBubbling { get; set; } = true; void OnControlLoaded(object sender, RoutedEventArgs e) { UpdateOnColor(); UpdateThumbColor(); Control.Loaded -= OnControlLoaded; } void OnNativeToggled(object sender, RoutedEventArgs routedEventArgs) { ((IElementController)Element).SetValueFromRenderer(Switch.IsToggledProperty, Control.IsOn); } void UpdateFlowDirection() { Control.UpdateFlowDirection(Element); } void UpdateOnColor() { if (Control == null) return; var grid = Control.GetFirstDescendant(); if (grid == null) return; var groups = WVisualStateManager.GetVisualStateGroups(grid); foreach (var group in groups) { if (group.Name != ToggleSwitchCommonStates) continue; foreach (var state in group.States) { if (state.Name != ToggleSwitchPointerOver) continue; foreach (var timeline in state.Storyboard.Children.OfType()) { var property = Storyboard.GetTargetProperty(timeline); var target = Storyboard.GetTargetName(timeline); if (target == ToggleSwitchKnobBounds && property == ToggleSwitchFillMode) { var frame = timeline.KeyFrames.FirstOrDefault(); if (frame != null) { if (_originalOnHoverColor == null) { if (frame.Value is WColor color) _originalOnHoverColor = color; if (frame.Value is SolidColorBrush solidColorBrush) _originalOnHoverColor = solidColorBrush; } if (!Element.OnColor.IsDefault) { frame.Value = new SolidColorBrush(Element.OnColor.ToWindowsColor()) { Opacity = _originalOnHoverColor is SolidColorBrush originalOnHoverBrush ? originalOnHoverBrush.Opacity : 1 }; } else frame.Value = _originalOnHoverColor; } break; } } } } var rect = Control.GetDescendantsByName(ToggleSwitchKnobBounds).FirstOrDefault(); if (rect != null) { if (_originalOnColorBrush == null) _originalOnColorBrush = rect.Fill; if (!Element.OnColor.IsDefault) rect.Fill = new SolidColorBrush(Element.OnColor.ToWindowsColor()); else rect.Fill = _originalOnColorBrush; } } void UpdateThumbColor() { if (Control == null) return; var grid = Control.GetFirstDescendant(); if (grid == null) return; var groups = WVisualStateManager.GetVisualStateGroups(grid); foreach (var group in groups) { if (group.Name != ToggleSwitchCommonStates) continue; foreach (var state in group.States) { if (state.Name != ToggleSwitchPointerOver) continue; foreach (var timeline in state.Storyboard.Children.OfType()) { var property = Storyboard.GetTargetProperty(timeline); var target = Storyboard.GetTargetName(timeline); if ((target == ToggleSwitchKnobOn) && (property == ToggleSwitchFillMode)) { var frame = timeline.KeyFrames.FirstOrDefault(); if (frame != null) { if (_originalThumbOnBrush == null) { if (frame.Value is global::Windows.UI.Color color) _originalOnColorBrush = new SolidColorBrush(color); if (frame.Value is Brush brush) _originalThumbOnBrush = brush; } if (!Element.ThumbColor.IsDefault) { var brush = Element.ThumbColor.ToBrush(); brush.Opacity = _originalThumbOnBrush.Opacity; frame.Value = brush; } else frame.Value = _originalThumbOnBrush; } break; } } } } if (grid.FindName(ToggleSwitchKnobOn) is Ellipse thumb) { if (_originalThumbOnBrush == null) _originalThumbOnBrush = thumb.Fill; if (!Element.ThumbColor.IsDefault) thumb.Fill = Element.ThumbColor.ToBrush(); else thumb.Fill = _originalThumbOnBrush; } } } }