maui-linux/Xamarin.Forms.Platform.WP8/EntryRenderer.cs

297 строки
9.1 KiB
C#

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
{
public 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;
Brush _textDefaultBrush;
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)
((IEntryController)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;
BrushHelpers.UpdateColor(Element.TextColor, ref _textDefaultBrush,
() => Control.Foreground, brush => Control.Foreground = brush);
// Force the PhoneTextBox control to do some internal bookkeeping
// so the colors change immediately and remain changed when the control gets focus
Control.OnApplyTemplate();
}
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()
{
BrushHelpers.UpdateColor(Element.PlaceholderColor, ref _placeholderDefaultBrush,
() => Control.PlaceholderForegroundBrush, brush => Control.PlaceholderForegroundBrush = brush);
}
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);
}
}
}