WPF의 숫자 데이터 입력
WPF 응용 프로그램에서 숫자 값 입력을 어떻게 처리하고 있습니까?
NumericUpDown 컨트롤이 없으면 텍스트 상자를 사용하고 아래 코드로 미리 보기 키다운 이벤트를 처리했지만 꽤나 추합니다.
타사 제어에 의존하지 않고 사용자로부터 숫자 데이터를 얻는 더 우아한 방법을 찾은 사람이 있습니까?
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}"/>
이 옵션은 사용자 지정 속성에서도 사용할 수 있습니다. 상자의 값이 잘못되어 컨트롤이 빨간색 테두리로 강조 표시되는 경우 예외를 던지기만 하면 됩니다.빨간색 테두리의 오른쪽 상단을 클릭하면 예외 메시지가 팝업됩니다.
나는 사용자가 위쪽 및 아래쪽 키를 사용하여 텍스트 상자의 값을 변경할 수 있도록 첨부된 속성을 사용해 왔습니다.그것을 사용하기 위해서, 당신은 단지.
<TextBox local:TextBoxNumbers.SingleDelta="1">100</TextBox>
이것은 실제로 이 질문에서 언급한 검증 문제를 다루지는 않지만 숫자 위/아래 컨트롤을 사용하지 않는 것에 대해 수행하는 작업을 다룹니다.조금만 사용해보면, 예전의 숫자 위/아래 컨트롤보다 더 마음에 들 것 같습니다.
코드가 완벽하지는 않지만 필요한 경우를 처리합니다.
Up
화표살,Down
Shift + Up
화표살,Shift + Down
Page Up
,Page Down
- 인딩
Converter
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);
미리 보기 키다운 이벤트보다 키다운 이벤트를 사용해 보는 것이 어떻습니까?여기서 잘못된 문자를 중지할 수 있지만 모든 제어 문자가 허용됩니다.이것은 저에게 효과가 있는 것 같습니다.
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);
}
지정 용자지사용정을 합니다.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>
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);
}
}
}
또한 적절한 종속성 속성을 제공하여 구문 분석 동작을 사용자 지정할 수 있습니다.
이 답변들 중 몇 가지에서 아이디어를 결합하여, 저는 다음과 같은 숫자 텍스트 상자를 만들었습니다.
- 소수점 이하를 처리합니다.
- 입력한 '-' 또는 '.'가 유효한지 확인하기 위한 기본적인 검증이 이루어집니까?
- 붙여넣은 값을 처리합니다.
포함되어야 할 다른 로직이 있다면 언제든지 업데이트해주시기 바랍니다.
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);
}
}
사용자가 데이터를 사용하기 전에 데이터를 커밋하는 경우에도 데이터 유효성 검사를 사용할 수 있습니다.그렇게 하는 것이 열쇠를 만지작거리는 것보다 꽤 간단하고 깨끗하다는 것을 알게 되었습니다.
그렇지 않으면 항상 붙여넣기를 비활성화할 수 있습니다!
My Version of Arcturus 답변은 int / tint / 10진수 / 바이트(색상의 경우) 또는 사용하려는 다른 숫자 형식으로 작업하는 데 사용되는 변환 방법을 변경할 수 있으며 복사/붙여넣기에도 사용할 수 있습니다.
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 );
}
N.B. 테스트되지 않은 코드.
텍스트 상자를 지울 때 바인딩이 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();
}
}
}
미친 사람이라고 부르세요. 하지만 텍스트 상자 컨트롤의 양쪽에 더하기와 빼기 버튼을 놓고 텍스트 상자가 커서 포커스를 수신하지 못하도록 하면 됩니다. 따라서 저렴한 수치 업다운 컨트롤을 만들 수 있습니다.
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;
}
}
이것이 제가 발견한 가장 쉬운 기술입니다.단점은 TextBox의 상황에 맞는 메뉴에서 Paste(붙여넣기)를 통해 숫자 이외의 숫자를 사용할 수 있다는 것입니다.이 문제를 빨리 해결하기 위해 ContextMenu="{x:Null}" 특성/키워드를 텍스트 상자에 추가하여 사용하지 않도록 설정했습니다.이상적이지는 않지만 제 시나리오로는 충분할 것입니다.
테스트에서 몇 개의 키/문자를 추가하여 허용 가능한 추가 값(예: '.', '$' 등)을 포함할 수 있습니다.
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
나를 위해 일했습니다.
다음과 같은 것만 사용할 수 없습니까?
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;
}
}
}
다음과 같은 변환기도 사용할 수 있습니다.
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
'source' 카테고리의 다른 글
Dispose()에서 obj = null(없음)을 설정할 수 있습니까? (0) | 2023.05.15 |
---|---|
분기 전환 및 커밋하지 않고 변경 사항 무시 (0) | 2023.05.15 |
Xcode 9의 "이 함수 선언은 프로토타입이 아닙니다" 경고 (0) | 2023.05.15 |
MongoDB에서 검색/프로젝션을 수행할 때 필드 이름을 변경하려면 어떻게 해야 합니까? (0) | 2023.05.15 |
특정 열의 날짜 형식을 "yyyy-mm-dd"로 설정하는 VBA 코드 (0) | 2023.05.15 |