using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using TabletTester2025.Views; namespace TabletTester2025.Helpers { public static class NumericInput { public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached( "IsEnabled", typeof(bool), typeof(NumericInput), new PropertyMetadata(false, OnIsEnabledChanged)); public static readonly DependencyProperty AllowDecimalProperty = DependencyProperty.RegisterAttached( "AllowDecimal", typeof(bool), typeof(NumericInput), new PropertyMetadata(true)); public static readonly DependencyProperty AllowNegativeProperty = DependencyProperty.RegisterAttached( "AllowNegative", typeof(bool), typeof(NumericInput), new PropertyMetadata(false)); private static readonly DependencyProperty IsKeypadOpenProperty = DependencyProperty.RegisterAttached( "IsKeypadOpen", typeof(bool), typeof(NumericInput), new PropertyMetadata(false)); public static readonly RoutedEvent ValueCommittedEvent = EventManager.RegisterRoutedEvent( "ValueCommitted", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(NumericInput)); public static void SetIsEnabled(DependencyObject element, bool value) => element.SetValue(IsEnabledProperty, value); public static bool GetIsEnabled(DependencyObject element) => (bool)element.GetValue(IsEnabledProperty); public static void SetAllowDecimal(DependencyObject element, bool value) => element.SetValue(AllowDecimalProperty, value); public static bool GetAllowDecimal(DependencyObject element) => (bool)element.GetValue(AllowDecimalProperty); public static void SetAllowNegative(DependencyObject element, bool value) => element.SetValue(AllowNegativeProperty, value); public static bool GetAllowNegative(DependencyObject element) => (bool)element.GetValue(AllowNegativeProperty); public static bool GetIsKeypadOpen(DependencyObject element) => (bool)element.GetValue(IsKeypadOpenProperty); public static void AddValueCommittedHandler(DependencyObject element, RoutedEventHandler handler) { if (element is UIElement uiElement) uiElement.AddHandler(ValueCommittedEvent, handler); } public static void RemoveValueCommittedHandler(DependencyObject element, RoutedEventHandler handler) { if (element is UIElement uiElement) uiElement.RemoveHandler(ValueCommittedEvent, handler); } private static void SetIsKeypadOpen(DependencyObject element, bool value) => element.SetValue(IsKeypadOpenProperty, value); private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not TextBox textBox) return; if ((bool)e.NewValue) { textBox.PreviewMouseLeftButtonDown += TextBox_PreviewMouseLeftButtonDown; textBox.PreviewTouchDown += TextBox_PreviewTouchDown; } else { textBox.PreviewMouseLeftButtonDown -= TextBox_PreviewMouseLeftButtonDown; textBox.PreviewTouchDown -= TextBox_PreviewTouchDown; } } private static void TextBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (sender is not TextBox textBox || !CanOpen(textBox)) return; e.Handled = true; OpenKeypad(textBox); } private static void TextBox_PreviewTouchDown(object sender, TouchEventArgs e) { if (sender is not TextBox textBox || !CanOpen(textBox)) return; e.Handled = true; OpenKeypad(textBox); } private static bool CanOpen(TextBox textBox) { return GetIsEnabled(textBox) && !GetIsKeypadOpen(textBox) && !textBox.IsReadOnly && textBox.IsEnabled; } private static void OpenKeypad(TextBox textBox) { SetIsKeypadOpen(textBox, true); try { var window = Window.GetWindow(textBox); var keypad = new NumericKeypadWindow( textBox.Text, GetAllowDecimal(textBox), GetAllowNegative(textBox)) { Owner = window }; if (keypad.ShowDialog() == true) { textBox.Text = string.IsNullOrWhiteSpace(keypad.ResultText) ? "0" : keypad.ResultText; textBox.GetBindingExpression(TextBox.TextProperty)?.UpdateSource(); textBox.RaiseEvent(new RoutedEventArgs(ValueCommittedEvent, textBox)); } } finally { SetIsKeypadOpen(textBox, false); Keyboard.ClearFocus(); } } } }