using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using Tango.SharedUI.Controls; namespace Tango.Touch.Controls { public class TouchNumericTextBox : TouchInput, IValueControl { private TextBox _text_box; private bool _prevent_text_change; private FastTextBlock _text_block; private double _lastValue; Regex regex_integer = new Regex(@"^-?[0-9]\d*(\d+)?$"); Regex regex_double = new Regex(@"^-?[0-9]\d*(\.\d+)?$"); public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(DoubleValueChangedEventHandler), typeof(TouchNumericTextBox)); public event DoubleValueChangedEventHandler ValueChanged { add { AddHandler(ValueChangedEvent, value); } remove { RemoveHandler(ValueChangedEvent, value); } } public static readonly RoutedEvent ValueChangedEndEvent = EventManager.RegisterRoutedEvent("ValueChangedEnd", RoutingStrategy.Bubble, typeof(DoubleValueChangedEventHandler), typeof(TouchNumericTextBox)); public event DoubleValueChangedEventHandler ValueChangedEnd { add { AddHandler(ValueChangedEndEvent, value); } remove { RemoveHandler(ValueChangedEndEvent, value); } } public static readonly RoutedEvent TextGotFocusEvent = EventManager.RegisterRoutedEvent("TextGotFocus", RoutingStrategy.Bubble, typeof(DoubleValueChangedEventHandler), typeof(TouchNumericTextBox)); public event DoubleValueChangedEventHandler TextGotFocus { add { AddHandler(TextGotFocusEvent, value); } remove { RemoveHandler(TextGotFocusEvent, value); } } public double Value { get { return (double)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(TouchNumericTextBox), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (d, e) => (d as TouchNumericTextBox).OnValueChanged(), (d, e) => (d as TouchNumericTextBox).CoerceValue(d, e), false, UpdateSourceTrigger.Explicit)); public String Watermark { get { return (String)GetValue(WatermarkProperty); } set { SetValue(WatermarkProperty, value); } } public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(String), typeof(TouchNumericTextBox), new PropertyMetadata(null)); public bool DisplayWatermarkHint { get { return (bool)GetValue(DisplayWatermarkHintProperty); } set { SetValue(DisplayWatermarkHintProperty, value); } } public static readonly DependencyProperty DisplayWatermarkHintProperty = DependencyProperty.Register("DisplayWatermarkHint", typeof(bool), typeof(TouchNumericTextBox), new PropertyMetadata(false)); public String StringFormat { get { return (String)GetValue(StringFormatProperty); } set { SetValue(StringFormatProperty, value); } } public static readonly DependencyProperty StringFormatProperty = DependencyProperty.Register("StringFormat", typeof(String), typeof(TouchNumericTextBox), new PropertyMetadata(null)); public bool HasDecimalPoint { get { return (bool)GetValue(HasDecimalPointProperty); } set { SetValue(HasDecimalPointProperty, value); } } public static readonly DependencyProperty HasDecimalPointProperty = DependencyProperty.Register("HasDecimalPoint", typeof(bool), typeof(TouchNumericTextBox), new PropertyMetadata(false)); public double Minimum { get { return (double)GetValue(MinimumProperty); } set { SetValue(MinimumProperty, value); } } public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(TouchNumericTextBox), new PropertyMetadata(0.0)); public double Maximum { get { return (double)GetValue(MaximumProperty); } set { SetValue(MaximumProperty, value); } } public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(TouchNumericTextBox), new PropertyMetadata(null)); public double JoggingFactor { get { return (double)GetValue(JoggingFactorProperty); } set { SetValue(JoggingFactorProperty, value); } } public static readonly DependencyProperty JoggingFactorProperty = DependencyProperty.Register("JoggingFactor", typeof(double), typeof(TouchNumericTextBox), new PropertyMetadata(1.0)); public bool AutoCalculateJogStep { get { return (bool)GetValue(AutoCalculateJogStepProperty); } set { SetValue(AutoCalculateJogStepProperty, value); } } public static readonly DependencyProperty AutoCalculateJogStepProperty = DependencyProperty.Register("AutoCalculateJogStep", typeof(bool), typeof(TouchNumericTextBox), new PropertyMetadata(true)); public bool UpdateBindingOnlyWhenFocused { get { return (bool)GetValue(UpdateBindingOnlyWhenFocusedProperty); } set { SetValue(UpdateBindingOnlyWhenFocusedProperty, value); } } public static readonly DependencyProperty UpdateBindingOnlyWhenFocusedProperty = DependencyProperty.Register("UpdateBindingOnlyWhenFocused", typeof(bool), typeof(TouchNumericTextBox), new PropertyMetadata(false)); public virtual bool HasError { get { return Validation.GetHasError(this); } } public override void OnApplyTemplate() { base.OnApplyTemplate(); _text_box = GetTemplateChild("PART_TextBox") as TextBox; _text_block = GetTemplateChild("PART_TextDisplay") as FastTextBlock; _text_box.PreviewTextInput += _text_box_PreviewTextInput; _text_box.PreviewKeyDown += _text_box_PreviewKeyDown; _text_box.LostFocus += _text_box_LostFocus; _text_box.GotFocus += _text_box_GotFocus; _text_box.TextChanged += _text_box_TextChanged; Value = Value; OnValueChanged(); } private async void _text_box_GotFocus(object sender, RoutedEventArgs e) { await Task.Delay(50); if (FocusSelectionMode == FocusSelectionMode.SelectAll) { _text_box.SelectAll(); } else if (FocusSelectionMode == FocusSelectionMode.ScrollToEnd) { _text_box.CaretIndex = _text_box.Text.Length; } DoubleValueChangedEventArgs args = new DoubleValueChangedEventArgs(TextGotFocusEvent, this, Value); RaiseEvent(args); } private object CoerceValue(DependencyObject d, object e) { double value = (double)e; if (_text_box != null) //Min and max not being set yet... { if (!HasDecimalPoint) { value = Math.Round(value, 0); } if (Maximum > Minimum) { if (value < Minimum) { value = Minimum; } else if (value > Maximum) { value = Maximum; } } } return value; } private void _text_box_LostFocus(object sender, RoutedEventArgs e) { double d = 0.0; if (double.TryParse(_text_box.Text, out d)) { Value = d; _text_box.Text = Value.ToString(); } _text_block.Text = Value.ToString(StringFormat); BindingExpression b = GetBindingExpression(ValueProperty); if (b != null) { b.UpdateSource(); } DoubleValueChangedEventArgs args = new DoubleValueChangedEventArgs(ValueChangedEvent, this, Value); RaiseEvent(args); DoubleValueChangedEventArgs args2 = new DoubleValueChangedEventArgs(ValueChangedEndEvent, this, Value); RaiseEvent(args2); } private void _text_box_PreviewKeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Space) { e.Handled = true; } } private void OnValueChanged() { if (_text_box != null && !_prevent_text_change) { _prevent_text_change = true; if (StringFormat != null) { _text_box.Text = Value.ToString(StringFormat); } else { _text_box.Text = Value.ToString(); } _text_block.Text = _text_box.Text; _prevent_text_change = false; } if (Value != _lastValue) { BindingExpression b = GetBindingExpression(ValueProperty); if (b != null) { b.UpdateSource(); } _lastValue = Value; if (!UpdateBindingOnlyWhenFocused || (_text_box != null && _text_box.IsKeyboardFocused)) { DoubleValueChangedEventArgs args = new DoubleValueChangedEventArgs(ValueChangedEvent, this, Value); RaiseEvent(args); } } } private void _text_box_PreviewTextInput(object sender, TextCompositionEventArgs e) { if (e.Text == "." && _text_box.Text.Contains('.')) { e.Handled = true; return; } else if(e.Text == "." && HasDecimalPoint) { e.Handled = false; return; } if (e.Text == "-" && !_text_box.Text.Contains("-")) { e.Handled = false; return; } else if (e.Text == "-") { e.Handled = true; return; } if (HasDecimalPoint) { e.Handled = !regex_double.IsMatch(e.Text); } else { e.Handled = !regex_integer.IsMatch(e.Text); } } private void _text_box_TextChanged(object sender, TextChangedEventArgs e) { if (_prevent_text_change) return; double d = 0.0; if (double.TryParse(_text_box.Text, out d)) { _prevent_text_change = true; Value = d; _prevent_text_change = false; } } static TouchNumericTextBox() { DefaultStyleKeyProperty.OverrideMetadata(typeof(TouchNumericTextBox), new FrameworkPropertyMetadata(typeof(TouchNumericTextBox))); } } }