WPF의 숫자 데이터 입력
WPF 응용 프로그램에서 숫자 값 입력을 어떻게 처리하고 있습니까?
NumericUpDown 컨트롤이 없으면 TextBox를 사용하고 아래 코드로 PreviewKeyDown 이벤트를 처리했지만 매우 추합니다.
타사 컨트롤에 의존하지 않고 사용자로부터 숫자 데이터를 얻는 더 우아한 방법을 찾은 사람이 있습니까?
private void NumericEditPreviewKeyDown(object sender, KeyEventArgs e)
{
bool isNumPadNumeric = (e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || e.Key == Key.Decimal;
bool isNumeric = (e.Key >= Key.D0 && e.Key <= Key.D9) || e.Key == Key.OemPeriod;
if ((isNumeric || isNumPadNumeric) && Keyboard.Modifiers != ModifierKeys.None)
{
e.Handled = true;
return;
}
bool isControl = ((Keyboard.Modifiers != ModifierKeys.None && Keyboard.Modifiers != ModifierKeys.Shift)
|| e.Key == Key.Back || e.Key == Key.Delete || e.Key == Key.Insert
|| e.Key == Key.Down || e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up
|| e.Key == Key.Tab
|| e.Key == Key.PageDown || e.Key == Key.PageUp
|| e.Key == Key.Enter || e.Key == Key.Return || e.Key == Key.Escape
|| e.Key == Key.Home || e.Key == Key.End);
e.Handled = !isControl && !isNumeric && !isNumPadNumeric;
}
어때 :
protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !AreAllValidNumericChars(e.Text);
base.OnPreviewTextInput(e);
}
private bool AreAllValidNumericChars(string str)
{
foreach(char c in str)
{
if(!Char.IsNumber(c)) return false;
}
return true;
}
이것이 내가하는 방법이다. 정규식을 사용하여 상자에 들어갈 텍스트가 숫자인지 여부를 확인합니다.
Regex NumEx = new Regex(@"^-?\d*\.?\d*$");
private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
if (sender is TextBox)
{
string text = (sender as TextBox).Text + e.Text;
e.Handled = !NumEx.IsMatch(text);
}
else
throw new NotImplementedException("TextBox_PreviewTextInput Can only Handle TextBoxes");
}
이제 WPF 및 Silverlight에서이 작업을 수행하는 훨씬 더 나은 방법이 있습니다. 컨트롤이 속성에 바인딩 된 경우 바인딩 문을 약간 변경하기 만하면됩니다. 바인딩에 다음을 사용하십시오.
<TextBox Text="{Binding Number, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/>
사용자 지정 속성에서도 이것을 사용할 수 있습니다. 상자의 값이 유효하지 않고 컨트롤이 빨간색 테두리로 강조 표시되면 예외를 throw하기 만하면됩니다. 빨간색 테두리의 오른쪽 상단을 클릭하면 예외 메시지가 나타납니다.
사용자가 위쪽 및 아래쪽 키를 사용하여 텍스트 상자의 값을 변경할 수 있도록 연결된 속성을 사용하고 있습니다. 그것을 사용하려면
<TextBox local:TextBoxNumbers.SingleDelta="1">100</TextBox>
이것은 실제로이 질문에서 언급 된 유효성 검사 문제를 해결하지 않지만 숫자 업 / 다운 컨트롤이없는 것에 대해 제가하는 일을 해결합니다. 조금만 사용하면 이전의 숫자 위 / 아래 컨트롤보다 실제로 더 좋을 것 같습니다.
이 코드는 완벽하지는 않지만 처리하는 데 필요한 경우를 처리합니다.
Up화살표,Down화살표Shift + Up화살표,Shift + Down화살표Page Up,Page DownConverter텍스트 속성에 바인딩
Code behind
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
namespace Helpers
{
public class TextBoxNumbers
{
public static Decimal GetSingleDelta(DependencyObject obj)
{
return (Decimal)obj.GetValue(SingleDeltaProperty);
}
public static void SetSingleDelta(DependencyObject obj, Decimal value)
{
obj.SetValue(SingleDeltaProperty, value);
}
// Using a DependencyProperty as the backing store for SingleValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SingleDeltaProperty =
DependencyProperty.RegisterAttached("SingleDelta", typeof(Decimal), typeof(TextBoxNumbers), new UIPropertyMetadata(0.0m, new PropertyChangedCallback(f)));
public static void f(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
TextBox t = o as TextBox;
if (t == null)
return;
t.PreviewKeyDown += new System.Windows.Input.KeyEventHandler(t_PreviewKeyDown);
}
private static Decimal GetSingleValue(DependencyObject obj)
{
return GetSingleDelta(obj);
}
private static Decimal GetDoubleValue(DependencyObject obj)
{
return GetSingleValue(obj) * 10;
}
private static Decimal GetTripleValue(DependencyObject obj)
{
return GetSingleValue(obj) * 100;
}
static void t_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
TextBox t = sender as TextBox;
Decimal i;
if (t == null)
return;
if (!Decimal.TryParse(t.Text, out i))
return;
switch (e.Key)
{
case System.Windows.Input.Key.Up:
if (Keyboard.Modifiers == ModifierKeys.Shift)
i += GetDoubleValue(t);
else
i += GetSingleValue(t);
break;
case System.Windows.Input.Key.Down:
if (Keyboard.Modifiers == ModifierKeys.Shift)
i -= GetDoubleValue(t);
else
i -= GetSingleValue(t);
break;
case System.Windows.Input.Key.PageUp:
i += GetTripleValue(t);
break;
case System.Windows.Input.Key.PageDown:
i -= GetTripleValue(t);
break;
default:
return;
}
if (BindingOperations.IsDataBound(t, TextBox.TextProperty))
{
try
{
Binding binding = BindingOperations.GetBinding(t, TextBox.TextProperty);
t.Text = (string)binding.Converter.Convert(i, null, binding.ConverterParameter, binding.ConverterCulture);
}
catch
{
t.Text = i.ToString();
}
}
else
t.Text = i.ToString();
}
}
}
LINQ 식을 사용하여 기본적으로 2 줄에 대한 답변으로 표시된 회신을 단순화하기로 결정했습니다.
e.Handled = !e.Text.All(Char.IsNumber);
base.OnPreviewTextInput(e);
사용자 지정 ValidationRule을 사용하여 텍스트가 숫자인지 확인합니다.
public class DoubleValidation : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
if (value is string)
{
double number;
if (!Double.TryParse((value as string), out number))
return new ValidationResult(false, "Please enter a valid number");
}
return ValidationResult.ValidResult;
}
그런 다음 a TextBox를 숫자 속성에 바인딩 할 때 새 사용자 지정 클래스를 Binding.ValidationRules컬렉션에 추가합니다 . 아래 예에서 유효성 검사 규칙은 TextBox.Text변경 될 때마다 확인 됩니다.
<TextBox>
<TextBox.Text>
<Binding Path="MyNumericProperty" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:DoubleValidation/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
PreviewKeyDown 이벤트 대신 KeyDown 이벤트를 사용해 보는 것은 어떨까요? 여기서 유효하지 않은 문자를 중지 할 수 있지만 모든 제어 문자가 허용됩니다. 이것은 나를 위해 작동하는 것 같습니다.
private void NumericKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
bool isNumPadNumeric = (e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9);
bool isNumeric =((e.Key >= Key.D0 && e.Key <= Key.D9) && (e.KeyboardDevice.Modifiers == ModifierKeys.None));
bool isDecimal = ((e.Key == Key.OemPeriod || e.Key == Key.Decimal) && (((TextBox)sender).Text.IndexOf('.') < 0));
e.Handled = !(isNumPadNumeric || isNumeric || isDecimal);
}
public class NumericTextBox : TextBox
{
public NumericTextBox()
: base()
{
DataObject.AddPastingHandler(this, new DataObjectPastingEventHandler(CheckPasteFormat));
}
private Boolean CheckFormat(string text)
{
short val;
return Int16.TryParse(text, out val);
}
private void CheckPasteFormat(object sender, DataObjectPastingEventArgs e)
{
var isText = e.SourceDataObject.GetDataPresent(System.Windows.DataFormats.Text, true);
if (isText)
{
var text = e.SourceDataObject.GetData(DataFormats.Text) as string;
if (CheckFormat(text))
{
return;
}
}
e.CancelCommand();
}
protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
{
if (!CheckFormat(e.Text))
{
e.Handled = true;
}
else
{
base.OnPreviewTextInput(e);
}
}
}
또한 적절한 종속성 속성을 제공하여 구문 분석 동작을 사용자 지정할 수 있습니다.
이 답변 중 몇 가지 아이디어를 결합하여 NumericTextBox를 만들었습니다.
- 소수 처리
- 입력 된 '-'또는 '.'를 확인하기 위해 몇 가지 기본 유효성 검사를 수행합니다. 유효하다
- 붙여 넣은 값 처리
포함되어야하는 다른 로직이 생각되면 언제든지 업데이트하십시오.
public class NumericTextBox : TextBox
{
public NumericTextBox()
{
DataObject.AddPastingHandler(this, OnPaste);
}
private void OnPaste(object sender, DataObjectPastingEventArgs dataObjectPastingEventArgs)
{
var isText = dataObjectPastingEventArgs.SourceDataObject.GetDataPresent(System.Windows.DataFormats.Text, true);
if (isText)
{
var text = dataObjectPastingEventArgs.SourceDataObject.GetData(DataFormats.Text) as string;
if (IsTextValid(text))
{
return;
}
}
dataObjectPastingEventArgs.CancelCommand();
}
private bool IsTextValid(string enteredText)
{
if (!enteredText.All(c => Char.IsNumber(c) || c == '.' || c == '-'))
{
return false;
}
//We only validation against unselected text since the selected text will be replaced by the entered text
var unselectedText = this.Text.Remove(SelectionStart, SelectionLength);
if (enteredText == "." && unselectedText.Contains("."))
{
return false;
}
if (enteredText == "-" && unselectedText.Length > 0)
{
return false;
}
return true;
}
protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !IsTextValid(e.Text);
base.OnPreviewTextInput(e);
}
}
사용자가 데이터를 사용하기 전에 커밋 한 경우 데이터 유효성 검사를 사용해 볼 수도 있습니다. 내가 찾은 것은 키를 조작하는 것보다 상당히 간단하고 깨끗했습니다.
그렇지 않으면 언제든지 붙여 넣기도 비활성화 할 수 있습니다!
내 버전의 Arcturus 답변은 int / uint / decimal / byte (색상) 또는 사용하려는 다른 숫자 형식으로 작업하는 데 사용되는 변환 방법을 변경할 수 있으며 복사 / 붙여 넣기와도 작동합니다.
protected override void OnPreviewTextInput( System.Windows.Input.TextCompositionEventArgs e )
{
try
{
if ( String.IsNullOrEmpty( SelectedText ) )
{
Convert.ToDecimal( this.Text.Insert( this.CaretIndex, e.Text ) );
}
else
{
Convert.ToDecimal( this.Text.Remove( this.SelectionStart, this.SelectionLength ).Insert( this.SelectionStart, e.Text ) );
}
}
catch
{
// mark as handled if cannot convert string to decimal
e.Handled = true;
}
base.OnPreviewTextInput( e );
}
NB 테스트되지 않은 코드.
이를 기본 솔루션에 추가하여 텍스트 상자가 지워질 때 바인딩이 0으로 업데이트되도록합니다.
protected override void OnPreviewKeyUp(System.Windows.Input.KeyEventArgs e)
{
base.OnPreviewKeyUp(e);
if (BindingOperations.IsDataBound(this, TextBox.TextProperty))
{
if (this.Text.Length == 0)
{
this.SetValue(TextBox.TextProperty, "0");
this.SelectAll();
}
}
}
Call me crazy, but why not put plus and minus buttons at either side of the TextBox control and simply prevent the TextBox from receiving cursor focus, thereby creating your own cheap NumericUpDown control?
private void txtNumericValue_PreviewKeyDown(object sender, KeyEventArgs e)
{
KeyConverter converter = new KeyConverter();
string key = converter.ConvertToString(e.Key);
if (key != null && key.Length == 1)
{
e.Handled = Char.IsDigit(key[0]) == false;
}
}
This is the easiest technique I've found to accomplish this. The down side is that the context menu of the TextBox still allows non-numerics via Paste. To resolve this quickly I simply added the attribute/property: ContextMenu="{x:Null}" to the TextBox thereby disabling it. Not ideal but for my scenario it will suffice.
Obviously you could add a few more keys/chars in the test to include additional acceptable values (e.g. '.', '$' etc...)
Private Sub Value1TextBox_PreviewTextInput(ByVal sender As Object, ByVal e As TextCompositionEventArgs) Handles Value1TextBox.PreviewTextInput
Try
If Not IsNumeric(e.Text) Then
e.Handled = True
End If
Catch ex As Exception
End Try
End Sub
Worked for me.
Can you not just use something like the following?
int numericValue = 0;
if (false == int.TryParse(yourInput, out numericValue))
{
// handle non-numeric input
}
void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
{
string sVal = e.Text;
int val = 0;
if (sVal != null && sVal.Length > 0)
{
if (int.TryParse(sVal, out val))
{
e.Handled = false;
}
else
{
e.Handled = true;
}
}
}
Can also use a converter like:
public class IntegerFormatConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int result;
int.TryParse(value.ToString(), out result);
return result;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int result;
int.TryParse(value.ToString(), out result);
return result;
}
}
참고URL : https://stackoverflow.com/questions/5511/numeric-data-entry-in-wpf
'Nice programing' 카테고리의 다른 글
| Java StringBuffer와 동등한 Python? (0) | 2020.11.21 |
|---|---|
| 도커 컨테이너 SSL 인증서 (0) | 2020.11.21 |
| C #의 큰 정수 (0) | 2020.11.21 |
| 자동 속성과 구조가 혼합되지 않습니까? (0) | 2020.11.21 |
| 어떤 크로스 브라우저 문제에 직면 했습니까? (0) | 2020.11.21 |