Dreamine.UI.Wpf.Equipment 1.0.1
Dreamine.UI.Wpf.Equipment 사용자 인터페이스 기능과 구성 요소를 제공합니다.
로딩중...
검색중...
일치하는것 없음
DreamineVirtualKeyboardUI.xaml.cs
이 파일의 문서화 페이지로 가기
1using System.Globalization;
2using System.Text.RegularExpressions;
3using System.Windows;
4using System.Windows.Controls;
5using System.Windows.Input;
6using System.Windows.Threading;
7using Dreamine.UI.Wpf.Controls;
8using Dreamine.UI.Abstractions.VirtualKeyboard;
10
12
22{
31 private readonly DispatcherTimer _debounceTimer;
32
41 public bool InternalUpdate { get; set; } = false;
42
51 public string Value
52 {
53 get => (string)GetValue(ValueProperty);
54 set => SetValue(ValueProperty, value);
55 }
56
65 public decimal Minimum
66 {
67 get => (decimal)GetValue(MinimumProperty);
68 set => SetValue(MinimumProperty, value);
69 }
70
79 public decimal Maximum
80 {
81 get => (decimal)GetValue(MaximumProperty);
82 set => SetValue(MaximumProperty, value);
83 }
84
93 public string DecimalFormat { get; set; } = string.Empty;
94
103 public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
104 nameof(Value), typeof(string), typeof(DreamineVirtualKeyboardUI),
105 new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
106
115 public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
116 nameof(Minimum), typeof(decimal), typeof(DreamineVirtualKeyboardUI),
117 new PropertyMetadata(decimal.MinValue));
118
127 public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
128 nameof(Maximum), typeof(decimal), typeof(DreamineVirtualKeyboardUI),
129 new PropertyMetadata(decimal.MaxValue));
130
140 {
141 InitializeComponent();
142
143 _debounceTimer = new DispatcherTimer(DispatcherPriority.SystemIdle, VkbTextBox.Dispatcher)
144 {
145 Interval = TimeSpan.FromSeconds(1),
146 };
147
151 }
152
162 {
163 VkbTextBox.Loaded += VkbInput_Loaded;
164 VkbTextBox.Unloaded += VkbInput_Unloaded;
165 VkbTextBox.IsVisibleChanged += VkbInput_IsVisibleChanged;
166 VkbPasswordBox.Loaded += VkbInput_Loaded;
167 VkbPasswordBox.Unloaded += VkbInput_Unloaded;
168 VkbPasswordBox.IsVisibleChanged += VkbInput_IsVisibleChanged;
169 }
170
195 private void VkbInput_Loaded(object sender, RoutedEventArgs e)
196 {
199 InternalUpdate = true;
200 if (Layout != VkLayout.Text && (string.IsNullOrEmpty(VkbTextBox.Text) || IsOuterRange()))
201 {
202 ClampNumericValue(true);
203 }
204 }
205
230 private void VkbInput_Unloaded(object sender, RoutedEventArgs e)
231 {
232 InternalUpdate = true;
233 _debounceTimer.Stop();
234 _debounceTimer.Tick -= NormalizeNumericInput;
235 }
236
269 private void VkbInput_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
270 {
273
274 if (Layout != VkLayout.Text && (string.IsNullOrEmpty(VkbTextBox.Text) || IsOuterRange()))
275 {
276 ClampNumericValue(true);
277 }
278
279 if ((bool)e.NewValue)
280 {
281 _debounceTimer.Tick -= NormalizeNumericInput;
282 _debounceTimer.Tick += NormalizeNumericInput;
283 }
284 else
285 {
286 _debounceTimer.Tick -= NormalizeNumericInput;
287 }
288 }
289
298 public void FocusVkbTextBox()
299 {
300 if (VkbTextBox.IsLoaded && VkbTextBox.IsVisible)
301 {
302 Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, () =>
303 {
304 VkbTextBox.Focus();
305 Keyboard.Focus(VkbTextBox);
306 VkbTextBox.CaretIndex = Math.Max(0, VkbTextBox.Text.Length);
307 });
308 }
309 }
310
320 {
321 if (VkbPasswordBox.IsLoaded && VkbPasswordBox.IsVisible)
322 {
323 Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, () =>
324 {
325 VkbPasswordBox.Focus();
326 Keyboard.Focus(VkbPasswordBox);
327 });
328 }
329 }
330
355 private void OnKeyboardLanguageChangedHandler(object? sender, LanguageCode e)
356 {
358 }
359
368 private void SetInputMethod()
369 {
370 switch (CurrentLang)
371 {
372 case LanguageCode.en_US:
373 InputMethod.SetIsInputMethodEnabled(VkbTextBox, false);
374 InputMethod.SetIsInputMethodSuspended(VkbTextBox, true);
375 break;
376 case LanguageCode.vi_VN:
377 InputMethod.SetIsInputMethodEnabled(VkbTextBox, false);
378 InputMethod.SetIsInputMethodSuspended(VkbTextBox, true);
379 break;
380 case LanguageCode.ko_KR:
381 case LanguageCode.zh_CN:
382 InputMethod.SetIsInputMethodEnabled(VkbTextBox, true);
383 InputMethod.SetIsInputMethodSuspended(VkbTextBox, false);
384 break;
385 }
386 }
387
397 {
398 var showMinMax = Layout != VkLayout.Text && (Minimum != decimal.MinValue || Maximum != decimal.MaxValue);
399 if (Layout == VkLayout.Numeric)
400 {
401 MinTbl.Visibility = showMinMax && Minimum != int.MinValue ? Visibility.Visible : Visibility.Collapsed;
402 MaxTbl.Visibility = showMinMax && Maximum != int.MaxValue ? Visibility.Visible : Visibility.Collapsed;
403 }
404 else if (Layout == VkLayout.Decimal)
405 {
406 MinTbl.Visibility = showMinMax && Minimum != decimal.MinValue ? Visibility.Visible : Visibility.Collapsed;
407 MaxTbl.Visibility = showMinMax && Maximum != decimal.MaxValue ? Visibility.Visible : Visibility.Collapsed;
408 }
409 else
410 {
411 MinTbl.Visibility = Visibility.Collapsed;
412 MaxTbl.Visibility = Visibility.Collapsed;
413 }
414 }
415
425 {
426 VkbTextBox.PreviewTextInput -= VkbTextBox_PreviewTextInput;
427 VkbTextBox.TextChanged -= VkbTextBox_TextChanged;
428 DataObject.RemovePastingHandler(VkbTextBox, VkbTextBox_OnTextBoxPasting);
429 }
430
440 {
442
443 if (Layout != VkLayout.Text)
444 {
445 VkbTextBox.PreviewTextInput += VkbTextBox_PreviewTextInput;
446 VkbTextBox.TextChanged += VkbTextBox_TextChanged;
447 DataObject.AddPastingHandler(VkbTextBox, VkbTextBox_OnTextBoxPasting);
448 }
449 }
450
460 {
461 VkbTextBox.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
462 }
463
488 private void VkbTextBox_TextChanged(object sender, TextChangedEventArgs e)
489 {
490 _debounceTimer.Stop();
491
492 if (!InternalUpdate)
493 {
494 _debounceTimer.Start();
495 }
496
497 if (InternalUpdate)
498 {
499 InternalUpdate = false;
500 }
501 }
502
535 private void NormalizeNumericInput(object? sender, EventArgs eventArgs)
536 {
537 var txt = VkbTextBox.Text;
538 if (Layout == VkLayout.Numeric)
539 {
540 if (decimal.TryParse(txt, NumberStyles.Integer, CultureInfo.InvariantCulture, out decimal intval))
541 {
542 var clamped = Math.Clamp(intval, Minimum, Maximum);
543 SetText(() =>
544 {
545 VkbTextBox.Text = clamped.ToString(CultureInfo.InvariantCulture);
546 VkbTextBox.CaretIndex = VkbTextBox.Text.Length;
547 });
548 }
549 }
550 else if (Layout == VkLayout.Decimal)
551 {
552 if (decimal.TryParse(txt, NumberStyles.Number, CultureInfo.InvariantCulture, out decimal decval))
553 {
554 decimal clamped = Math.Clamp(decval, Minimum, Maximum);
555 if (!txt.EndsWith(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator))
556 {
557 SetText(() =>
558 {
559 FormatDecimalValue(clamped);
560 });
561 }
562 }
563 }
564
565 _debounceTimer.Stop();
566 }
567
592 private void FormatDecimalValue(decimal decimalVal)
593 {
594 SetText(() =>
595 {
596 VkbTextBox.Text = string.IsNullOrEmpty(DecimalFormat) ? decimalVal.ToString(CultureInfo.InvariantCulture) : decimalVal.ToString(DecimalFormat, CultureInfo.InvariantCulture);
597 VkbTextBox.CaretIndex = VkbTextBox.Text.Length;
598 });
599 }
600
633 private void VkbTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
634 {
635 if (Layout == VkLayout.Decimal)
636 {
637 var sep = CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator;
638
639 if (e.Text == sep && !VkbTextBox.Text.Contains(sep))
640 {
641 e.Handled = false;
642 return;
643 }
644 }
645 var proposedText = VkbTextBox.Text.Insert(VkbTextBox.CaretIndex, e.Text);
646 e.Handled = !IsValidNumericInput(proposedText);
647 }
648
689 private void VkbTextBox_OnTextBoxPasting(object sender, DataObjectPastingEventArgs e)
690 {
691 if (e.DataObject.GetDataPresent(DataFormats.Text))
692 {
693 var text = (string)e.DataObject.GetData(DataFormats.Text);
694 if (!IsValidNumericInput(text))
695 e.CancelCommand();
696 }
697 else
698 e.CancelCommand();
699 }
700
725 private void SetText(Action action)
726 {
727 InternalUpdate = true;
728 action.Invoke();
729 }
730
763 private bool IsValidNumericInput(string input)
764 {
765 if (Layout == VkLayout.Numeric)
766 return Regex.IsMatch(input, @"^-?[0-9]*$");
767 else
768 {
769 var sep = CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator;
770 string esc = Regex.Escape(sep);
771 return Regex.IsMatch(input, @"^-?[0-9]*(" + esc + @"[0-9]*)?$");
772 }
773 }
774
799 public void ClampNumericValue(bool updateSourceBinding = false)
800 {
801 if (Layout == VkLayout.Numeric)
802 {
803 decimal.TryParse(VkbTextBox.Text, NumberStyles.Integer, CultureInfo.InvariantCulture, out decimal intval);
804 var clamped = Math.Clamp(intval, Minimum, Maximum);
805 SetText(() =>
806 {
807 VkbTextBox.Text = clamped.ToString(CultureInfo.InvariantCulture);
808 VkbTextBox.CaretIndex = VkbTextBox.Text.Length;
809 });
810 }
811 else if (Layout == VkLayout.Decimal)
812 {
813 decimal.TryParse(VkbTextBox.Text, NumberStyles.Number, CultureInfo.InvariantCulture, out decimal decval);
814 decimal clamped = Math.Clamp(decval, Minimum, Maximum);
815 if (!VkbTextBox.Text.EndsWith(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator))
816 {
817 SetText(() =>
818 {
819 FormatDecimalValue(clamped);
820 });
821 }
822 }
823
824 if (updateSourceBinding)
825 {
826 VkbTextBox.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
827 }
828 }
829
846 public bool IsOuterRange()
847 {
848 if (Layout == VkLayout.Numeric)
849 {
850 var isSuccess = decimal.TryParse(VkbTextBox.Text, NumberStyles.Integer, CultureInfo.InvariantCulture, out decimal intval);
851 if (!isSuccess || intval < Minimum || intval > Maximum)
852 {
853 return true;
854 }
855 }
856 else if (Layout == VkLayout.Decimal)
857 {
858 var isSuccess = decimal.TryParse(VkbTextBox.Text, NumberStyles.Number, CultureInfo.InvariantCulture, out decimal decval);
859 if (!isSuccess || decval < Minimum || decval > Maximum)
860 {
861 return true;
862 }
863 }
864
865 return false;
866 }
867}
void VkbInput_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)