From efe25a8f8b57ccf6e80b8522eafad123051d17b6 Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Tue, 8 Nov 2016 09:32:05 -0800 Subject: [PATCH] fix(TextInput): Perform more accurate measurement for PasswordBox (#856) `PasswordBox.Measure(size)` does not result in a value being set for `PasswordBox.DesiredSize` property. The same goes for `TextBox`, which we worked around by measuring a `TextBlock` and including the `TextBox` margin values in the resulting measurement. Making the same change for `PasswordBox`. Fixes #855 --- .../TextInput/ReactPasswordBoxShadowNode.cs | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/ReactWindows/ReactNative/Views/TextInput/ReactPasswordBoxShadowNode.cs b/ReactWindows/ReactNative/Views/TextInput/ReactPasswordBoxShadowNode.cs index c2433ed1bf..814ef09ff0 100644 --- a/ReactWindows/ReactNative/Views/TextInput/ReactPasswordBoxShadowNode.cs +++ b/ReactWindows/ReactNative/Views/TextInput/ReactPasswordBoxShadowNode.cs @@ -7,7 +7,9 @@ using ReactNative.Views.Text; using System; using Windows.Foundation; using Windows.UI.Text; +using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Documents; using Windows.UI.Xaml.Media; namespace ReactNative.Views.TextInput @@ -18,6 +20,8 @@ namespace ReactNative.Views.TextInput /// public class ReactPasswordBoxShadowNode : LayoutShadowNode { + private static string s_passwordChar; + private const int Unset = -1; private float[] _computedPadding; @@ -221,19 +225,25 @@ namespace ReactNative.Views.TextInput { var textNode = (ReactPasswordBoxShadowNode)node; - var passwordBox = new PasswordBox(); + var textBlock = new TextBlock + { + TextWrapping = TextWrapping.Wrap, + }; - var normalizedText = string.IsNullOrEmpty(textNode._text) ? " " : textNode._text; - FormatPasswordBox(textNode, passwordBox, true); + var passwordChar = GetDefaultPasswordChar(); + var normalizedText = !string.IsNullOrEmpty(textNode._text) + ? new string(passwordChar[0], textNode._text.Length) + : passwordChar; + var inline = new Run { Text = normalizedText }; + FormatTextElement(textNode, inline); + textBlock.Inlines.Add(inline); - passwordBox.Password = normalizedText; - - passwordBox.Measure(new Size(normalizedWidth, normalizedHeight)); + textBlock.Measure(new Size(normalizedWidth, normalizedHeight)); var borderTopWidth = textInputNode.GetBorder(CSSSpacingType.Top); var borderBottomWidth = textInputNode.GetBorder(CSSSpacingType.Bottom); - var finalizedHeight = (float)passwordBox.DesiredSize.Height; + var finalizedHeight = (float)textBlock.DesiredSize.Height; finalizedHeight += textInputNode._computedPadding[1]; finalizedHeight += textInputNode._computedPadding[3]; finalizedHeight += CSSConstants.IsUndefined(borderTopWidth) ? 0 : borderTopWidth; @@ -245,36 +255,41 @@ namespace ReactNative.Views.TextInput return task.Result; } - /// - /// Formats an inline instance with shadow properties. - /// - /// The text shadow node. - /// The password box. - /// Signals if the operation is used only for measurement. - protected static void FormatPasswordBox(ReactPasswordBoxShadowNode textNode, Control box, bool measureOnly) + private static string GetDefaultPasswordChar() + { + if (s_passwordChar == null) + { + var passwordBox = new PasswordBox(); + s_passwordChar = passwordBox.PasswordChar; + } + + return s_passwordChar; + } + + private static void FormatTextElement(ReactPasswordBoxShadowNode textNode, TextElement inline) { if (textNode._fontSize != Unset) { var fontSize = textNode._fontSize; - box.FontSize = fontSize; + inline.FontSize = fontSize; } if (textNode._fontStyle.HasValue) { var fontStyle = textNode._fontStyle.Value; - box.FontStyle = fontStyle; + inline.FontStyle = fontStyle; } if (textNode._fontWeight.HasValue) { var fontWeight = textNode._fontWeight.Value; - box.FontWeight = fontWeight; + inline.FontWeight = fontWeight; } if (textNode._fontFamily != null) { var fontFamily = new FontFamily(textNode._fontFamily); - box.FontFamily = fontFamily; + inline.FontFamily = fontFamily; } } }