using System; using System.Collections.Generic; using System.ComponentModel; using System.Text.RegularExpressions; using System.Xml.Linq; using Windows.Foundation; using Windows.UI.Text; using Windows.UI.Xaml; using Windows.UI.Xaml.Automation.Peers; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Documents; using Xamarin.Forms.Platform.UAP; using Xamarin.Forms.PlatformConfiguration.WindowsSpecific; using Specifics = Xamarin.Forms.PlatformConfiguration.WindowsSpecific.Label; using WThickness = Windows.UI.Xaml.Thickness; namespace Xamarin.Forms.Platform.UWP { public static class FormattedStringExtensions { public static Run ToRun(this Span span) { var run = new Run { Text = span.Text ?? string.Empty }; if (span.TextColor != Color.Default) run.Foreground = span.TextColor.ToBrush(); if (!span.IsDefault()) #pragma warning disable 618 run.ApplyFont(span.Font); #pragma warning restore 618 if (span.IsSet(Span.TextDecorationsProperty)) run.TextDecorations = (Windows.UI.Text.TextDecorations)span.TextDecorations; run.CharacterSpacing = span.CharacterSpacing.ToEm(); return run; } } public class LabelRenderer : ViewRenderer { bool _fontApplied; bool _isInitiallyDefault; SizeRequest _perfectSize; bool _perfectSizeValid; IList _inlineHeights = new List(); //TODO: We need to revisit this later when we complete the UI Tests for UWP. // Changing the AutomationPeer here prevents the Narrator from functioning properly. // Oddly, it affects more than just the TextBlocks. It seems to break the entire scan mode. //protected override AutomationPeer OnCreateAutomationPeer() //{ // // We need an automation peer so we can interact with this in automated tests // if (Control == null) // { // return new FrameworkElementAutomationPeer(this); // } // return new TextBlockAutomationPeer(Control); //} protected override Windows.Foundation.Size ArrangeOverride(Windows.Foundation.Size finalSize) { if (Element == null) return finalSize; double childHeight = Math.Max(0, Math.Min(Element.Height, Control.DesiredSize.Height)); var rect = new Rect(); switch (Element.VerticalTextAlignment) { case TextAlignment.Start: break; default: case TextAlignment.Center: rect.Y = (int)((finalSize.Height - childHeight) / 2); break; case TextAlignment.End: rect.Y = finalSize.Height - childHeight; break; } rect.Height = childHeight; rect.Width = finalSize.Width; Control.Arrange(rect); Control.RecalculateSpanPositions(Element, _inlineHeights); return finalSize; } public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint) { if (!_perfectSizeValid) { _perfectSize = base.GetDesiredSize(double.PositiveInfinity, double.PositiveInfinity); _perfectSize.Minimum = new Size(Math.Min(10, _perfectSize.Request.Width), _perfectSize.Request.Height); _perfectSizeValid = true; } var widthFits = widthConstraint >= _perfectSize.Request.Width; var heightFits = heightConstraint >= _perfectSize.Request.Height; if (widthFits && heightFits) return _perfectSize; var result = base.GetDesiredSize(widthConstraint, heightConstraint); var tinyWidth = Math.Min(10, result.Request.Width); result.Minimum = new Size(tinyWidth, result.Request.Height); if (widthFits || Element.LineBreakMode == LineBreakMode.NoWrap) return result; bool containerIsNotInfinitelyWide = !double.IsInfinity(widthConstraint); if (containerIsNotInfinitelyWide) { bool textCouldHaveWrapped = Element.LineBreakMode == LineBreakMode.WordWrap || Element.LineBreakMode == LineBreakMode.CharacterWrap; bool textExceedsContainer = result.Request.Width > widthConstraint; if (textExceedsContainer || textCouldHaveWrapped) { var expandedWidth = Math.Max(tinyWidth, widthConstraint); result.Request = new Size(expandedWidth, result.Request.Height); } } return result; } protected override void OnElementChanged(ElementChangedEventArgs