Dreamine.UI.Wpf 1.0.1
Dreamine.UI.Wpf 사용자 인터페이스 기능과 구성 요소를 제공합니다.
로딩중...
검색중...
일치하는것 없음
NumericRangeBehavior.cs
이 파일의 문서화 페이지로 가기
1using System;
2using System.Globalization;
3using System.Windows;
4using System.Windows.Controls;
5using System.Windows.Input;
6
8{
17 public enum NumericRangeMode
18 {
37 }
38
55 public static class NumericRangeBehavior
56 {
65 public static readonly DependencyProperty IsEnabledProperty =
66 DependencyProperty.RegisterAttached(
67 "IsEnabled",
68 typeof(bool),
70 new PropertyMetadata(false, OnIsEnabledChanged));
71
80 public static readonly DependencyProperty MinProperty =
81 DependencyProperty.RegisterAttached(
82 "Min",
83 typeof(double?),
85 new PropertyMetadata(null));
86
95 public static readonly DependencyProperty MaxProperty =
96 DependencyProperty.RegisterAttached(
97 "Max",
98 typeof(double?),
100 new PropertyMetadata(null));
101
110 public static readonly DependencyProperty ModeProperty =
111 DependencyProperty.RegisterAttached(
112 "Mode",
113 typeof(NumericRangeMode),
114 typeof(NumericRangeBehavior),
115 new PropertyMetadata(NumericRangeMode.Clamp));
116
125 private static readonly DependencyProperty LastValidTextProperty =
126 DependencyProperty.RegisterAttached(
127 "LastValidText",
128 typeof(string),
129 typeof(NumericRangeBehavior),
130 new PropertyMetadata(null));
131
156 public static void SetIsEnabled(DependencyObject d, bool value) => d.SetValue(IsEnabledProperty, value);
181 public static bool GetIsEnabled(DependencyObject d) => (bool)d.GetValue(IsEnabledProperty);
182
207 public static void SetMin(DependencyObject d, double? value) => d.SetValue(MinProperty, value);
232 public static double? GetMin(DependencyObject d) => (double?)d.GetValue(MinProperty);
233
258 public static void SetMax(DependencyObject d, double? value) => d.SetValue(MaxProperty, value);
283 public static double? GetMax(DependencyObject d) => (double?)d.GetValue(MaxProperty);
284
309 public static void SetMode(DependencyObject d, NumericRangeMode value) => d.SetValue(ModeProperty, value);
334 public static NumericRangeMode GetMode(DependencyObject d) => (NumericRangeMode)d.GetValue(ModeProperty);
335
360 private static void SetLastValidText(DependencyObject d, string value) => d.SetValue(LastValidTextProperty, value);
385 private static string GetLastValidText(DependencyObject d) => (string)d.GetValue(LastValidTextProperty);
386
411 private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
412 {
413 if (d is not TextBox tb) return;
414
415 if ((bool)e.NewValue)
416 {
417 tb.Loaded += Tb_Loaded;
418 tb.TextChanged += Tb_TextChanged;
419 tb.LostFocus += Tb_LostFocus;
420 DataObject.AddPastingHandler(tb, OnPasting);
421 }
422 else
423 {
424 tb.Loaded -= Tb_Loaded;
425 tb.TextChanged -= Tb_TextChanged;
426 tb.LostFocus -= Tb_LostFocus;
427 DataObject.RemovePastingHandler(tb, OnPasting);
428 }
429 }
430
455 private static void Tb_Loaded(object sender, RoutedEventArgs e)
456 {
457 if (sender is TextBox tb)
458 SetLastValidText(tb, tb.Text);
459 }
460
485 private static void OnPasting(object sender, DataObjectPastingEventArgs e)
486 {
487 if (sender is not TextBox tb) return;
488
489 if (e.DataObject.GetDataPresent(DataFormats.UnicodeText))
490 {
491 var pasteText = e.DataObject.GetData(DataFormats.UnicodeText) as string ?? string.Empty;
492 var future = GetFutureText(tb, pasteText);
493 if (!TryValidate(tb, future, out var corrected))
494 {
495 if (GetMode(tb) == NumericRangeMode.Reject)
496 {
497 e.CancelCommand();
498 tb.Text = GetLastValidText(tb) ?? string.Empty;
499 tb.CaretIndex = tb.Text.Length;
500 return;
501 }
502 e.CancelCommand(); // Clamp
503 tb.Text = corrected;
504 tb.CaretIndex = tb.Text.Length;
505 }
506 }
507 }
508
541 private static void Tb_TextChanged(object sender, TextChangedEventArgs e)
542 {
543 if (sender is not TextBox tb) return;
544
545 if (GetMode(tb) == NumericRangeMode.Clamp)
546 {
547 if (!TryValidate(tb, tb.Text, out var corrected))
548 {
549 tb.TextChanged -= Tb_TextChanged;
550 tb.Text = corrected;
551 tb.CaretIndex = tb.Text.Length;
552 tb.TextChanged += Tb_TextChanged;
553 }
554 else
555 {
556 SetLastValidText(tb, tb.Text);
557 }
558 }
559 }
560
585 private static void Tb_LostFocus(object sender, RoutedEventArgs e)
586 {
587 if (sender is not TextBox tb) return;
588
589 var mode = GetMode(tb);
590 if (!TryValidate(tb, tb.Text, out var corrected))
591 {
592 tb.Text = (mode == NumericRangeMode.Reject)
593 ? (GetLastValidText(tb) ?? corrected)
594 : corrected;
595 }
596 SetLastValidText(tb, tb.Text);
597
598 // 바인딩 원본 반영
599 var expr = tb.GetBindingExpression(TextBox.TextProperty);
600 expr?.UpdateSource();
601 }
602
643 private static string GetFutureText(TextBox tb, string insert)
644 {
645 var text = tb.Text ?? string.Empty;
646 var selStart = tb.SelectionStart;
647 var selLen = tb.SelectionLength;
648 if (selLen > 0) text = text.Remove(selStart, selLen);
649 return text.Insert(selStart, insert);
650 }
651
692 private static bool TryValidate(TextBox tb, string text, out string corrected)
693 {
694 corrected = text ?? string.Empty;
695 if (string.IsNullOrWhiteSpace(text))
696 return true; // 빈값 허용 여부는 별도 정책에서 결정
697
698 var style = NumberStyles.Float | NumberStyles.AllowThousands;
699 var culture = CultureInfo.CurrentCulture;
700
701 if (!double.TryParse(text, style, culture, out var value))
702 {
703 return false; // 숫자 아님
704 }
705
706 var min = GetMin(tb);
707 var max = GetMax(tb);
708
709 if (min.HasValue && value < min.Value)
710 {
711 corrected = min.Value.ToString(culture);
712 return false;
713 }
714 if (max.HasValue && value > max.Value)
715 {
716 corrected = max.Value.ToString(culture);
717 return false;
718 }
719
720 return true;
721 }
722 }
723}
static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
static void SetMode(DependencyObject d, NumericRangeMode value)
static void SetMin(DependencyObject d, double? value)
static readonly DependencyProperty MaxProperty
static string GetLastValidText(DependencyObject d)
static void Tb_TextChanged(object sender, TextChangedEventArgs e)
static bool TryValidate(TextBox tb, string text, out string corrected)
static string GetFutureText(TextBox tb, string insert)
static readonly DependencyProperty IsEnabledProperty
static void SetIsEnabled(DependencyObject d, bool value)
static void SetMax(DependencyObject d, double? value)
static void OnPasting(object sender, DataObjectPastingEventArgs e)
static readonly DependencyProperty LastValidTextProperty
static readonly DependencyProperty MinProperty
static NumericRangeMode GetMode(DependencyObject d)
static void SetLastValidText(DependencyObject d, string value)
static void Tb_LostFocus(object sender, RoutedEventArgs e)
static void Tb_Loaded(object sender, RoutedEventArgs e)
static readonly DependencyProperty ModeProperty