diff options
Diffstat (limited to 'Xamarin.Forms.Platform.WP8/EntryRenderer.cs')
-rw-r--r-- | Xamarin.Forms.Platform.WP8/EntryRenderer.cs | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.WP8/EntryRenderer.cs b/Xamarin.Forms.Platform.WP8/EntryRenderer.cs new file mode 100644 index 00000000..f96ca312 --- /dev/null +++ b/Xamarin.Forms.Platform.WP8/EntryRenderer.cs @@ -0,0 +1,324 @@ +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Input; +using System.Windows.Media; +using static System.String; +using WControl = System.Windows.Controls.Control; + +namespace Xamarin.Forms.Platform.WinPhone +{ + internal static class KeyboardExtensions + { + public static InputScope ToInputScope(this Keyboard self) + { + var result = new InputScope(); + var name = new InputScopeName(); + if (self == Keyboard.Default) + name.NameValue = InputScopeNameValue.Default; + else if (self == Keyboard.Chat) + name.NameValue = InputScopeNameValue.Chat; + else if (self == Keyboard.Email) + name.NameValue = InputScopeNameValue.EmailNameOrAddress; + else if (self == Keyboard.Numeric) + name.NameValue = InputScopeNameValue.Number; + else if (self == Keyboard.Telephone) + name.NameValue = InputScopeNameValue.TelephoneNumber; + else if (self == Keyboard.Text) + name.NameValue = InputScopeNameValue.Text; + else if (self == Keyboard.Url) + name.NameValue = InputScopeNameValue.Url; + else if (self is CustomKeyboard) + { + var custom = (CustomKeyboard)self; + bool capitalizedSentenceEnabled = (custom.Flags & KeyboardFlags.CapitalizeSentence) == KeyboardFlags.CapitalizeSentence; + bool spellcheckEnabled = (custom.Flags & KeyboardFlags.Spellcheck) == KeyboardFlags.Spellcheck; + bool suggestionsEnabled = (custom.Flags & KeyboardFlags.Suggestions) == KeyboardFlags.Suggestions; + + if (!capitalizedSentenceEnabled && !spellcheckEnabled && !suggestionsEnabled) + name.NameValue = InputScopeNameValue.Default; + if (!capitalizedSentenceEnabled && !spellcheckEnabled && suggestionsEnabled) + name.NameValue = InputScopeNameValue.Search; + if (!capitalizedSentenceEnabled && spellcheckEnabled && !suggestionsEnabled) + { + Debug.WriteLine("Keyboard: Suggestions cannot be disabled in Windows Phone if spellcheck is enabled"); + name.NameValue = InputScopeNameValue.Search; + } + if (!capitalizedSentenceEnabled && spellcheckEnabled && suggestionsEnabled) + name.NameValue = InputScopeNameValue.Search; + if (capitalizedSentenceEnabled && !spellcheckEnabled && !suggestionsEnabled) + { + Debug.WriteLine("Keyboard: Suggestions cannot be disabled in Windows Phone if auto Capitalization is enabled"); + name.NameValue = InputScopeNameValue.Chat; + } + if (capitalizedSentenceEnabled && !spellcheckEnabled && suggestionsEnabled) + name.NameValue = InputScopeNameValue.Chat; + if (capitalizedSentenceEnabled && spellcheckEnabled && !suggestionsEnabled) + { + Debug.WriteLine("Keyboard: Suggestions cannot be disabled in Windows Phone if spellcheck is enabled"); + name.NameValue = InputScopeNameValue.Text; + } + if (capitalizedSentenceEnabled && spellcheckEnabled && suggestionsEnabled) + name.NameValue = InputScopeNameValue.Text; + } + else + { + // Should never happens + name.NameValue = InputScopeNameValue.Default; + } + result.Names.Add(name); + return result; + } + } + + public class EntryRenderer : ViewRenderer<Entry, FormsPhoneTextBox> + { + bool _fontApplied; + bool _ignoreTextChange; + Brush _placeholderDefaultBrush; + + public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint) + { + if (Children.Count == 0) + return new SizeRequest(); + + var constraint = new System.Windows.Size(widthConstraint, heightConstraint); + + FormsPhoneTextBox child = Control; + + double oldWidth = child.Width; + double oldHeight = child.Height; + + child.Height = double.NaN; + child.Width = double.NaN; + + child.Measure(constraint); + var result = new Size(Math.Ceiling(child.DesiredSize.Width), Math.Ceiling(child.DesiredSize.Height)); + + child.Width = oldWidth; + child.Height = oldHeight; + + return new SizeRequest(result); + } + + protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) + { + base.OnElementChanged(e); + + var textBox = new FormsPhoneTextBox(); + + SetNativeControl(textBox); + + UpdateInputScope(); + UpdateIsPassword(); + UpdateText(); + UpdatePlaceholder(); + UpdateColor(); + UpdateFont(); + UpdateAlignment(); + UpdatePlaceholderColor(); + UpdateIsEnabled(); + + Control.LostFocus += OnTextBoxUnfocused; + Control.TextChanged += TextBoxOnTextChanged; + Control.KeyUp += TextBoxOnKeyUp; + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) + { + base.OnElementPropertyChanged(sender, e); + + if (e.PropertyName == Entry.TextProperty.PropertyName) + UpdateText(); + else if (e.PropertyName == Entry.PlaceholderProperty.PropertyName) + UpdatePlaceholder(); + else if (e.PropertyName == Entry.IsPasswordProperty.PropertyName) + UpdateIsPassword(); + else if (e.PropertyName == VisualElement.IsEnabledProperty.PropertyName) + UpdateIsEnabled(); + else if (e.PropertyName == Entry.TextColorProperty.PropertyName) + UpdateColor(); + else if (e.PropertyName == InputView.KeyboardProperty.PropertyName) + UpdateInputScope(); + else if (e.PropertyName == Entry.FontAttributesProperty.PropertyName) + UpdateFont(); + else if (e.PropertyName == Entry.FontFamilyProperty.PropertyName) + UpdateFont(); + else if (e.PropertyName == Entry.FontSizeProperty.PropertyName) + UpdateFont(); + else if (e.PropertyName == Entry.HorizontalTextAlignmentProperty.PropertyName) + UpdateAlignment(); + else if (e.PropertyName == Entry.PlaceholderColorProperty.PropertyName) + UpdatePlaceholderColor(); + } + + protected override void UpdateBackgroundColor() + { + Control.Background = Element.BackgroundColor.IsDefault ? (Brush)System.Windows.Application.Current.Resources["PhoneTextBoxBrush"] : Element.BackgroundColor.ToBrush(); + } + + internal override void OnModelFocusChangeRequested(object sender, VisualElement.FocusRequestArgs args) + { + if (args.Focus) + args.Result = Control.Focus(); + else + { + UnfocusControl(Control); + args.Result = true; + } + } + + void OnTextBoxUnfocused(object sender, RoutedEventArgs e) + { + if (Element.TextColor.IsDefault) + return; + + if (!IsNullOrEmpty(Element.Text)) + Control.Foreground = Element.TextColor.ToBrush(); + } + + void TextBoxOnKeyUp(object sender, KeyEventArgs keyEventArgs) + { + if (keyEventArgs.Key == Key.Enter) + Element.SendCompleted(); + } + + void TextBoxOnTextChanged(object sender, System.Windows.Controls.TextChangedEventArgs textChangedEventArgs) + { + // Signal to the UpdateText method that the change to TextProperty doesn't need to update the control + // This prevents the cursor position from getting lost + _ignoreTextChange = true; + ((IElementController)Element).SetValueFromRenderer(Entry.TextProperty, Control.Text); + + // If an Entry.TextChanged handler modified the value of the Entry's text, the values could now be + // out-of-sync; re-sync them and force the TextBox cursor to the end of the text + string entryText = Element.Text; + if (Control.Text != entryText) + { + Control.Text = entryText; + Control.SelectionStart = Control.Text.Length; + } + + _ignoreTextChange = false; + } + + void UpdateAlignment() + { + if (Control == null) + return; + + Control.TextAlignment = Element.HorizontalTextAlignment.ToNativeTextAlignment(); + } + + void UpdateColor() + { + if (Control == null) + return; + + Entry entry = Element; + if (entry != null) + { + if (!IsNullOrEmpty(entry.Text)) + { + if (!entry.TextColor.IsDefault) + Control.Foreground = entry.TextColor.ToBrush(); + else + Control.Foreground = (Brush)WControl.ForegroundProperty.GetMetadata(typeof(FormsPhoneTextBox)).DefaultValue; + + // Force the PhoneTextBox control to do some internal bookkeeping + // so the colors change immediately and remain changed when the control gets focus + Control.OnApplyTemplate(); + } + } + else + Control.Foreground = (Brush)WControl.ForegroundProperty.GetMetadata(typeof(FormsPhoneTextBox)).DefaultValue; + } + + void UpdateFont() + { + if (Control == null) + return; + + Entry entry = Element; + + if (entry == null) + return; + + bool entryIsDefault = entry.FontFamily == null && entry.FontSize == Device.GetNamedSize(NamedSize.Default, typeof(Entry), true) && entry.FontAttributes == FontAttributes.None; + + if (entryIsDefault && !_fontApplied) + return; + + if (entryIsDefault) + { + Control.ClearValue(WControl.FontStyleProperty); + Control.ClearValue(WControl.FontSizeProperty); + Control.ClearValue(WControl.FontFamilyProperty); + Control.ClearValue(WControl.FontWeightProperty); + Control.ClearValue(WControl.FontStretchProperty); + } + else + Control.ApplyFont(entry); + + _fontApplied = true; + } + + void UpdateInputScope() + { + Control.InputScope = Element.Keyboard.ToInputScope(); + } + + void UpdateIsEnabled() + { + Control.IsEnabled = Element.IsEnabled; + } + + void UpdateIsPassword() + { + Control.IsPassword = Element.IsPassword; + } + + void UpdatePlaceholder() + { + Control.Hint = Element.Placeholder ?? ""; + } + + void UpdatePlaceholderColor() + { + Color placeholderColor = Element.PlaceholderColor; + + if (placeholderColor.IsDefault) + { + if (_placeholderDefaultBrush == null) + return; + + // Use the cached default brush + Control.PlaceholderForegroundBrush = _placeholderDefaultBrush; + return; + } + + if (_placeholderDefaultBrush == null) + { + // Cache the default brush in case we need to set the color back to default + _placeholderDefaultBrush = Control.PlaceholderForegroundBrush; + } + + Control.PlaceholderForegroundBrush = placeholderColor.ToBrush(); + } + + void UpdateText() + { + // If the text property has changed because TextBoxOnTextChanged called SetValueFromRenderer, + // we don't want to re-update the text and reset the cursor position + if (_ignoreTextChange) + return; + + if (Control.Text == Element.Text) + return; + + Control.Text = Element.Text ?? ""; + Control.Select(Control.Text.Length, 0); + } + } +}
\ No newline at end of file |