From 5af224a1e7679a618149ecac2aa0d8b7eb6cb629 Mon Sep 17 00:00:00 2001 From: "E.Z. Hart" Date: Fri, 3 Feb 2017 11:13:53 -0700 Subject: [PATCH] Fix disappearing ListView text when changing color settings on Windows (#731) * repro * Checkpoint * Checkpoint * Remove now-unnecessary hacks for Time- and DatePicker --- .../Bugzilla40139.cs | 88 ++++++++++++++++++++++ .../Xamarin.Forms.Controls.Issues.Shared.projitems | 1 + .../Xamarin.Forms.Platform.UAP.csproj | 9 --- Xamarin.Forms.Platform.WinRT/DatePickerRenderer.cs | 18 +---- Xamarin.Forms.Platform.WinRT/FormsDatePicker.cs | 76 ------------------- Xamarin.Forms.Platform.WinRT/FormsTimePicker.cs | 77 ------------------- Xamarin.Forms.Platform.WinRT/IWrapperAware.cs | 14 ---- Xamarin.Forms.Platform.WinRT/TimePickerRenderer.cs | 21 +----- .../ViewToRendererConverter.cs | 29 +------ .../Xamarin.Forms.Platform.WinRT.csproj | 3 - 10 files changed, 98 insertions(+), 238 deletions(-) create mode 100644 Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla40139.cs delete mode 100644 Xamarin.Forms.Platform.WinRT/FormsDatePicker.cs delete mode 100644 Xamarin.Forms.Platform.WinRT/FormsTimePicker.cs delete mode 100644 Xamarin.Forms.Platform.WinRT/IWrapperAware.cs diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla40139.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla40139.cs new file mode 100644 index 0000000..a79d32a --- /dev/null +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla40139.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using Xamarin.Forms.CustomAttributes; +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 40139, "Changing the Windows 10 System Theme Color causes ListView text to disappear.", + PlatformAffected.WinRT)] + public class Bugzilla40139 : TestContentPage + { + protected override void Init() + { + var lv = new ListView + { + ItemsSource = new List + { + Color.Aqua, + Color.Black, + Color.Blue, + Color.Fuchsia, + Color.Gray, + Color.Green, + Color.Lime, + Color.Maroon, + Color.Navy + }, + BackgroundColor = Color.Gray, + ItemTemplate = new DataTemplate(typeof(_40139ViewCell)) + }; + + var layout = new StackLayout + { + Children = + { + new Label + { + Text = + "On your machine, go to Settings -> Personalization -> Colors and change the accent color for your system. If the text of the controls in the list disappears, this test has failed." + }, + lv + } + }; + + Content = layout; + } + + [Preserve(AllMembers = true)] + public class _40139ViewCell : ViewCell + { + public _40139ViewCell() + { + var label = new Label + { + Text = "abc", + VerticalOptions = LayoutOptions.Center, + TextColor = Color.White, + FontFamily = "Consolas", + FontSize = 24, + BackgroundColor = Color.Chartreuse + }; + + var entry = new Entry + { + Placeholder = "Placeholder", + TextColor = Color.Coral + }; + + var button = new Button + { + Text = "Button", + TextColor = Color.Coral + }; + + var layout = new StackLayout(); + layout.Children.Add(label); + + layout.Children.Add(entry); + layout.Children.Add(button); + + var image = new Image { Source = "coffee.png" }; + layout.Children.Add(image); + + View = layout; + } + } + } +} \ 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 a6829a8..859f3c0 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 @@ -110,6 +110,7 @@ + diff --git a/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj b/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj index ec7bca5..b1ae854 100644 --- a/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj +++ b/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj @@ -140,12 +140,6 @@ FormsComboBox.cs - - FormsDatePicker.cs - - - FormsTimePicker.cs - HorizontalTextAlignmentConverter.cs @@ -155,9 +149,6 @@ IToolbarProvider.cs - - IWrapperAware.cs - NativeBindingExtensions.cs diff --git a/Xamarin.Forms.Platform.WinRT/DatePickerRenderer.cs b/Xamarin.Forms.Platform.WinRT/DatePickerRenderer.cs index 646d7d3..677563e 100644 --- a/Xamarin.Forms.Platform.WinRT/DatePickerRenderer.cs +++ b/Xamarin.Forms.Platform.WinRT/DatePickerRenderer.cs @@ -13,23 +13,14 @@ namespace Xamarin.Forms.Platform.UWP namespace Xamarin.Forms.Platform.WinRT #endif { - public class DatePickerRenderer : ViewRenderer, IWrapperAware + public class DatePickerRenderer : ViewRenderer { Brush _defaultBrush; - public void NotifyWrapped() - { - if (Control != null) - { - Control.ForceInvalidate += PickerOnForceInvalidate; - } - } - protected override void Dispose(bool disposing) { if (disposing && Control != null) { - Control.ForceInvalidate -= PickerOnForceInvalidate; Control.DateChanged -= OnControlDateChanged; Control.Loaded -= ControlOnLoaded; } @@ -43,7 +34,7 @@ namespace Xamarin.Forms.Platform.WinRT { if (Control == null) { - var picker = new FormsDatePicker(); + var picker = new Windows.UI.Xaml.Controls.DatePicker(); SetNativeControl(picker); Control.Loaded += ControlOnLoaded; Control.DateChanged += OnControlDateChanged; @@ -89,11 +80,6 @@ namespace Xamarin.Forms.Platform.WinRT ((IVisualElementController)Element).InvalidateMeasure(InvalidationTrigger.SizeRequestChanged); } - void PickerOnForceInvalidate(object sender, EventArgs eventArgs) - { - ((IVisualElementController)Element)?.InvalidateMeasure(InvalidationTrigger.SizeRequestChanged); - } - void UpdateDate(DateTime date) { Control.Date = date; diff --git a/Xamarin.Forms.Platform.WinRT/FormsDatePicker.cs b/Xamarin.Forms.Platform.WinRT/FormsDatePicker.cs deleted file mode 100644 index 4412742..0000000 --- a/Xamarin.Forms.Platform.WinRT/FormsDatePicker.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using Windows.UI.Core; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; - -#if WINDOWS_UWP - -namespace Xamarin.Forms.Platform.UWP -#else - -namespace Xamarin.Forms.Platform.WinRT -#endif -{ - public class FormsDatePicker : Windows.UI.Xaml.Controls.DatePicker - { - public FormsDatePicker() - { - if (Device.Idiom == TargetIdiom.Desktop || Device.Idiom == TargetIdiom.Tablet) - { - Loaded += (sender, args) => { Window.Current.Activated += WindowOnActivated; }; - Unloaded += (sender, args) => { Window.Current.Activated -= WindowOnActivated; }; - } - } - - public event EventHandler ForceInvalidate; - - protected override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - if (Device.Idiom == TargetIdiom.Desktop || Device.Idiom == TargetIdiom.Tablet) - { - // Look for the combo boxes which make up a DatePicker on Windows 8.1 - // So we can hook into their closed events and invalidate them if necessary - - var dayPicker = GetTemplateChild("DayPicker") as ComboBox; - if (dayPicker != null) - { - dayPicker.DropDownClosed += PickerOnDropDownClosed; - } - - var monthPicker = GetTemplateChild("MonthPicker") as ComboBox; - if (monthPicker != null) - { - monthPicker.DropDownClosed += PickerOnDropDownClosed; - } - - var yearPicker = GetTemplateChild("YearPicker") as ComboBox; - if (yearPicker != null) - { - yearPicker.DropDownClosed += PickerOnDropDownClosed; - } - } - } - - void PickerOnDropDownClosed(object sender, object o) - { - // If the DatePicker is in a TableView or ListView and the user - // opens one of the dropdowns but does not actually change the value, - // when the dropdown closes, the selected value will go blank - // To fix this, we have to invalidate the control - // This only applies to Windows 8.1 - ForceInvalidate?.Invoke(this, EventArgs.Empty); - } - - void WindowOnActivated(object sender, WindowActivatedEventArgs windowActivatedEventArgs) - { - // If the DatePicker is in a TableView or ListView, when the application loses and then regains focus - // the TextBlock/ComboBox controls (UWP and 8.1, respectively) which display its selected value - // will go blank. - // To fix this, we have to signal the renderer to invalidate if - // Window.Activated occurs. - ForceInvalidate?.Invoke(this, EventArgs.Empty); - } - } -} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.WinRT/FormsTimePicker.cs b/Xamarin.Forms.Platform.WinRT/FormsTimePicker.cs deleted file mode 100644 index c135a58..0000000 --- a/Xamarin.Forms.Platform.WinRT/FormsTimePicker.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using Windows.UI.Core; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Media; - -#if WINDOWS_UWP - -namespace Xamarin.Forms.Platform.UWP -#else - -namespace Xamarin.Forms.Platform.WinRT -#endif -{ - public class FormsTimePicker : Windows.UI.Xaml.Controls.TimePicker - { - public FormsTimePicker() - { - if (Device.Idiom == TargetIdiom.Desktop || Device.Idiom == TargetIdiom.Tablet) - { - Loaded += (sender, args) => { Window.Current.Activated += WindowOnActivated; }; - Unloaded += (sender, args) => { Window.Current.Activated -= WindowOnActivated; }; - } - } - - public event EventHandler ForceInvalidate; - - protected override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - if (Device.Idiom == TargetIdiom.Desktop || Device.Idiom == TargetIdiom.Tablet) - { - // Look for the combo boxes which make up a TimePicker on Windows 8.1 - // So we can hook into their closed events and invalidate them if necessary - - var hourPicker = GetTemplateChild("HourPicker") as ComboBox; - if (hourPicker != null) - { - hourPicker.DropDownClosed += PickerOnDropDownClosed; - } - - var minutePicker = GetTemplateChild("MinutePicker") as ComboBox; - if (minutePicker != null) - { - minutePicker.DropDownClosed += PickerOnDropDownClosed; - } - - var periodPicker = GetTemplateChild("PeriodPicker") as ComboBox; - if (periodPicker != null) - { - periodPicker.DropDownClosed += PickerOnDropDownClosed; - } - } - } - - void PickerOnDropDownClosed(object sender, object o) - { - // If the TimePicker is in a TableView or ListView and the user - // opens one of the dropdowns but does not actually change the value, - // when the dropdown closes, the selected value will go blank - // To fix this, we have to invalidate the control - // This only applies to Windows 8.1 - ForceInvalidate?.Invoke(this, EventArgs.Empty); - } - - void WindowOnActivated(object sender, WindowActivatedEventArgs windowActivatedEventArgs) - { - // If the TimePicker is in a TableView or ListView, when the application loses focus - // the TextBlock/ComboBox controls (UWP and 8.1, respectively) which display its selected value - // will go blank. - // To fix this, we have to signal the renderer to invalidate if - // Window.Activated occurs. - ForceInvalidate?.Invoke(this, EventArgs.Empty); - } - } -} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.WinRT/IWrapperAware.cs b/Xamarin.Forms.Platform.WinRT/IWrapperAware.cs deleted file mode 100644 index aff9013..0000000 --- a/Xamarin.Forms.Platform.WinRT/IWrapperAware.cs +++ /dev/null @@ -1,14 +0,0 @@ - -#if WINDOWS_UWP - -namespace Xamarin.Forms.Platform.UWP -#else - -namespace Xamarin.Forms.Platform.WinRT -#endif -{ - internal interface IWrapperAware - { - void NotifyWrapped(); - } -} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.WinRT/TimePickerRenderer.cs b/Xamarin.Forms.Platform.WinRT/TimePickerRenderer.cs index 0095cdc..59ce8fc 100644 --- a/Xamarin.Forms.Platform.WinRT/TimePickerRenderer.cs +++ b/Xamarin.Forms.Platform.WinRT/TimePickerRenderer.cs @@ -1,5 +1,4 @@ -using System; -using System.ComponentModel; +using System.ComponentModel; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; @@ -13,23 +12,14 @@ namespace Xamarin.Forms.Platform.UWP namespace Xamarin.Forms.Platform.WinRT #endif { - public class TimePickerRenderer : ViewRenderer, IWrapperAware + public class TimePickerRenderer : ViewRenderer { Brush _defaultBrush; - public void NotifyWrapped() - { - if (Control != null) - { - Control.ForceInvalidate += PickerOnForceInvalidate; - } - } - protected override void Dispose(bool disposing) { if (disposing && Control != null) { - Control.ForceInvalidate -= PickerOnForceInvalidate; Control.TimeChanged -= OnControlTimeChanged; Control.Loaded -= ControlOnLoaded; } @@ -45,7 +35,7 @@ namespace Xamarin.Forms.Platform.WinRT { if (Control == null) { - var picker = new FormsTimePicker(); + var picker = new Windows.UI.Xaml.Controls.TimePicker(); SetNativeControl(picker); Control.TimeChanged += OnControlTimeChanged; @@ -81,11 +71,6 @@ namespace Xamarin.Forms.Platform.WinRT ((IVisualElementController)Element)?.InvalidateMeasure(InvalidationTrigger.SizeRequestChanged); } - void PickerOnForceInvalidate(object sender, EventArgs eventArgs) - { - ((IVisualElementController)Element)?.InvalidateMeasure(InvalidationTrigger.SizeRequestChanged); - } - void UpdateTime() { Control.Time = Element.Time; diff --git a/Xamarin.Forms.Platform.WinRT/ViewToRendererConverter.cs b/Xamarin.Forms.Platform.WinRT/ViewToRendererConverter.cs index 3d5906d..1512425 100644 --- a/Xamarin.Forms.Platform.WinRT/ViewToRendererConverter.cs +++ b/Xamarin.Forms.Platform.WinRT/ViewToRendererConverter.cs @@ -2,7 +2,6 @@ using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; -using Xamarin.Forms.Internals; #if WINDOWS_UWP @@ -38,11 +37,11 @@ namespace Xamarin.Forms.Platform.WinRT throw new NotSupportedException(); } - class WrapperControl : ContentControl + class WrapperControl : Canvas { readonly View _view; - FrameworkElement FrameworkElement => Content as FrameworkElement; + FrameworkElement FrameworkElement { get; } public WrapperControl(View view) { @@ -52,9 +51,8 @@ namespace Xamarin.Forms.Platform.WinRT IVisualElementRenderer renderer = Platform.CreateRenderer(view); Platform.SetRenderer(view, renderer); - NotifyWrapperAwareDescendants(view, renderer); - - Content = renderer.ContainerElement; + FrameworkElement = renderer.ContainerElement; + Children.Add(renderer.ContainerElement); // make sure we re-measure once the template is applied if (FrameworkElement != null) @@ -100,25 +98,6 @@ namespace Xamarin.Forms.Platform.WinRT return result; } - - void NotifyWrapperAwareDescendants(Element currentView, IVisualElementRenderer currentRenderer) - { - // If any of the child renderers need to handle anything differently because they're in - // a wrapper in a list view, let them know that they're being wrapped - var wrapperAwareRenderer = currentRenderer as IWrapperAware; - wrapperAwareRenderer?.NotifyWrapped(); - - foreach (Element child in ((IElementController)currentView).LogicalChildren) - { - var childView = child as View; - if (childView == null) - { - continue; - } - - NotifyWrapperAwareDescendants(childView, Platform.GetRenderer(childView)); - } - } } } } \ No newline at end of file diff --git a/Xamarin.Forms.Platform.WinRT/Xamarin.Forms.Platform.WinRT.csproj b/Xamarin.Forms.Platform.WinRT/Xamarin.Forms.Platform.WinRT.csproj index 766fd72..339e192 100644 --- a/Xamarin.Forms.Platform.WinRT/Xamarin.Forms.Platform.WinRT.csproj +++ b/Xamarin.Forms.Platform.WinRT/Xamarin.Forms.Platform.WinRT.csproj @@ -80,9 +80,6 @@ - - - -- 2.7.4