WPF에서 TextBox에 숫자 입력 만 허용하려면 어떻게해야합니까?


335

숫자와 소수점을 허용하려고하지만 부호는 없습니다.

Windows Forms 용 NumericUpDown 컨트롤을 사용하는 샘플과 Microsoft의 NumericUpDown 사용자 지정 컨트롤 샘플을 살펴 보았습니다 . 그러나 지금까지 NumericUpDown (WPF에서 지원 여부)은 원하는 기능을 제공하지 않는 것처럼 보입니다. 내 응용 프로그램이 디자인 된 방식으로 올바른 마음을 가진 사람은 화살표를 엉망으로 만들지 않을 것입니다. 그들은 내 응용 프로그램의 맥락에서 실용적인 의미가 없습니다.

그래서 표준 WPF TextBox에서 원하는 문자 만 허용하는 간단한 방법을 찾고 있습니다. 이게 가능해? 실용적입니까?

답변:


418

미리보기 텍스트 입력 이벤트를 추가하십시오. 그렇습니다 : <TextBox PreviewTextInput="PreviewTextInput" />.

그런 다음 그 안에 e.Handled텍스트가 허용되지 않는 경우 를 설정하십시오 .e.Handled = !IsTextAllowed(e.Text);

IsTextAllowed방법에 간단한 정규식을 사용하여 입력 한 것을 허용 해야하는지 확인합니다. 제 경우에는 숫자, 점 및 대시 만 허용하고 싶습니다.

private static readonly Regex _regex = new Regex("[^0-9.-]+"); //regex that matches disallowed text
private static bool IsTextAllowed(string text)
{
    return !_regex.IsMatch(text);
}

잘못된 데이터를 붙여 넣지 않으려면 다음 과 같이 DataObject.Pasting이벤트 DataObject.Pasting="TextBoxPasting"를 연결 하십시오 (코드 발췌).

// Use the DataObject.Pasting Handler 
private void TextBoxPasting(object sender, DataObjectPastingEventArgs e)
{
    if (e.DataObject.GetDataPresent(typeof(String)))
    {
        String text = (String)e.DataObject.GetData(typeof(String));
        if (!IsTextAllowed(text))
        {
            e.CancelCommand();
        }
    }
    else
    {
        e.CancelCommand();
    }
}

5
정규식은 과학적 표기법 (1e5)이 중요하다면 허용하지 않습니다.
Ron Warholic

14
이 답변은 입력 한 내용 만 확인하므로 3-.3을 입력 할 수 있습니다.
David Sykes

153
대답의 핵심은 완벽한 정규식을 지정하는 것이 아니라 WPF를 사용하여 다른 사람이 입력하는 것을 필터링하는 방법을 보여주는 것이 었습니다.
Ray

27
[Space]는 PreviewTextInput 이벤트를 발생시키지 않습니다.
peterG 2008 년

5
뭔가 등 double.TryParse()아마 라인 같은 수의 구현보다 유연하게 될 것이다.
Thomas Weller

190

이벤트 핸들러가 텍스트 입력을 미리보고 있습니다. 여기서 정규식은 숫자가 아닌 경우에만 텍스트 입력과 일치하며 입력 텍스트 상자에 입력되지 않습니다.

문자 만 원하면 정규식을로 바꾸십시오 [^a-zA-Z].

XAML

<TextBox Name="NumberTextBox" PreviewTextInput="NumberValidationTextBox"/>

XAML.CS 파일

using System.Text.RegularExpressions;
private void NumberValidationTextBox(object sender, TextCompositionEventArgs e)
{
    Regex regex = new Regex("[^0-9]+");
    e.Handled = regex.IsMatch(e.Text);
}

1
이벤트 핸들러는 미리보기 텍스트 입력입니다. 여기서 정규식은 숫자가 아닌 경우에만 텍스트 입력과 일치하며 입력 텍스트 상자에 입력되지 않습니다. 알파벳 만 원하는 경우 정규식을 [^ a-zA-Z]로 바꾸십시오.
Kishor

숫자, 소수 및 연산자는 어떻습니까?
Jason Ebersey 2014 년

다른 STATIC 클래스에서 선언하고 텍스트 상자에 적용 할 때 사용하는 방법을 알려주십시오.
SHEKHAR SHETE

3
나는 이것을 짧고 간단한 실제 답변보다 더 좋아합니다. 실제 답변에는 동일한 결과를 얻기 위해 두 가지 방법이 필요합니다.
은색

1
@Jagd 제안 된 답변은 더 나은 우려 분리입니다. 그러나이 유효성 검사에서도 많은 텍스트 상자를 설정할 수 있습니다. PreviewTextInput = "NumberValidationTextBox"를 추가하십시오. (다른 답변과 마찬가지로!)
은색

84

나는 이미 여기에있는 것들 중 일부를 사용했고 행동을 사용하여 내 자신의 비틀기를 넣었으므로 많은 코드를 통해이 코드를 전파 할 필요가 없습니다 ...

public class AllowableCharactersTextBoxBehavior : Behavior<TextBox>
{
    public static readonly DependencyProperty RegularExpressionProperty =
         DependencyProperty.Register("RegularExpression", typeof(string), typeof(AllowableCharactersTextBoxBehavior),
         new FrameworkPropertyMetadata(".*"));
    public string RegularExpression
    {
        get
        {
            return (string)base.GetValue(RegularExpressionProperty);
        }
        set
        {
            base.SetValue(RegularExpressionProperty, value);
        }
    }

    public static readonly DependencyProperty MaxLengthProperty =
        DependencyProperty.Register("MaxLength", typeof(int), typeof(AllowableCharactersTextBoxBehavior),
        new FrameworkPropertyMetadata(int.MinValue));
    public int MaxLength
    {
        get
        {
            return (int)base.GetValue(MaxLengthProperty);
        }
        set
        {
            base.SetValue(MaxLengthProperty, value);
        }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewTextInput += OnPreviewTextInput;
        DataObject.AddPastingHandler(AssociatedObject, OnPaste);
    }

    private void OnPaste(object sender, DataObjectPastingEventArgs e)
    {
        if (e.DataObject.GetDataPresent(DataFormats.Text))
        {
            string text = Convert.ToString(e.DataObject.GetData(DataFormats.Text));

            if (!IsValid(text, true))
            {
                e.CancelCommand();
            }
        }
        else
        {
            e.CancelCommand();
        }
    }

    void OnPreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
    {
        e.Handled = !IsValid(e.Text, false);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.PreviewTextInput -= OnPreviewTextInput;
        DataObject.RemovePastingHandler(AssociatedObject, OnPaste);
    }

    private bool IsValid(string newText, bool paste)
    {
        return !ExceedsMaxLength(newText, paste) && Regex.IsMatch(newText, RegularExpression);
    }

    private bool ExceedsMaxLength(string newText, bool paste)
    {
        if (MaxLength == 0) return false;

        return LengthOfModifiedText(newText, paste) > MaxLength;
    }

    private int LengthOfModifiedText(string newText, bool paste)
    {
        var countOfSelectedChars = this.AssociatedObject.SelectedText.Length;
        var caretIndex = this.AssociatedObject.CaretIndex;
        string text = this.AssociatedObject.Text;

        if (countOfSelectedChars > 0 || paste)
        {
            text = text.Remove(caretIndex, countOfSelectedChars);
            return text.Length + newText.Length;
        }
        else
        {
            var insert = Keyboard.IsKeyToggled(Key.Insert);

            return insert && caretIndex < text.Length ? text.Length : text.Length + newText.Length;
        }
    }
}

관련 뷰 코드는 다음과 같습니다.

<TextBox MaxLength="50" TextWrapping="Wrap" MaxWidth="150" Margin="4"
 Text="{Binding Path=FileNameToPublish}" >
     <interactivity:Interaction.Behaviors>
         <v:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9.\-]+$" MaxLength="50" />
     </interactivity:Interaction.Behaviors>
</TextBox>

1
이 멋진 솔루션에서 영감을 얻어 몇 가지 개선 사항을 구현했습니다. 실에서 아래를 확인하십시오.
Alex Klaus

2
안녕하세요. 나는 이것이 조금 늦다는 것을 알고 있지만 이것을 구현하려고하지만 오류가 계속 발생합니다. 참조가 누락 된 것 같습니다. 클래스를 만든 후 기본값 이외의 다른 유형을 입력해야합니까?
제공

1
@Offer 예, xaml 창의 맨 위에 xmlns : interactivity = " schemas.microsoft.com/expression/2010/interactivity "를 포함 시키십시오.
WiteCastle

표현은 이제 더 이상 사용되지 않습니다. 이 방법은 깨끗하지만 더 이상 유지 관리되지 않는 코드를 사용하고 있습니다.
Robert Baker

1
따라서 IsValid 함수를 편집하여! ExceedsMaxLength (newText, paste) && Regex.IsMatch (String.Concat (this.AssociatedObject.Text, newText), RegularExpression); 그러면 전체 문자열이 평가됩니다. Btw-행동으로이 옵션을 좋아하십시오 !!
Rogala

59

이것은 WilP 의 답변을 개선 한 솔루션입니다 . 내 개선 사항은 다음과 같습니다

  • DelBackspace 버튼의 동작 개선
  • EmptyValue빈 문자열이 부적절한 경우 속성 추가
  • 사소한 오타 수정
/// <summary>
///     Regular expression for Textbox with properties: 
///         <see cref="RegularExpression"/>, 
///         <see cref="MaxLength"/>,
///         <see cref="EmptyValue"/>.
/// </summary>
public class TextBoxInputRegExBehaviour : Behavior<TextBox>
{
    #region DependencyProperties
    public static readonly DependencyProperty RegularExpressionProperty =
        DependencyProperty.Register("RegularExpression", typeof(string), typeof(TextBoxInputRegExBehaviour), new FrameworkPropertyMetadata(".*"));

    public string RegularExpression
    {
        get { return (string)GetValue(RegularExpressionProperty); }
        set { SetValue(RegularExpressionProperty, value); }
    }

    public static readonly DependencyProperty MaxLengthProperty =
        DependencyProperty.Register("MaxLength", typeof(int), typeof(TextBoxInputRegExBehaviour),
                                        new FrameworkPropertyMetadata(int.MinValue));

    public int MaxLength
    {
        get { return (int)GetValue(MaxLengthProperty); }
        set { SetValue(MaxLengthProperty, value); }
    }

    public static readonly DependencyProperty EmptyValueProperty =
        DependencyProperty.Register("EmptyValue", typeof(string), typeof(TextBoxInputRegExBehaviour), null);

    public string EmptyValue
    {
        get { return (string)GetValue(EmptyValueProperty); }
        set { SetValue(EmptyValueProperty, value); }
    }
    #endregion

    /// <summary>
    ///     Attach our behaviour. Add event handlers
    /// </summary>
    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.PreviewTextInput += PreviewTextInputHandler;
        AssociatedObject.PreviewKeyDown += PreviewKeyDownHandler;
        DataObject.AddPastingHandler(AssociatedObject, PastingHandler);
    }

    /// <summary>
    ///     Deattach our behaviour. remove event handlers
    /// </summary>
    protected override void OnDetaching()
    {
        base.OnDetaching();

        AssociatedObject.PreviewTextInput -= PreviewTextInputHandler;
        AssociatedObject.PreviewKeyDown -= PreviewKeyDownHandler;
        DataObject.RemovePastingHandler(AssociatedObject, PastingHandler);
    }

    #region Event handlers [PRIVATE] --------------------------------------

    void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
    {
        string text;
        if (this.AssociatedObject.Text.Length < this.AssociatedObject.CaretIndex)
            text = this.AssociatedObject.Text;
        else
        {
            //  Remaining text after removing selected text.
            string remainingTextAfterRemoveSelection;

            text = TreatSelectedText(out remainingTextAfterRemoveSelection)
                ? remainingTextAfterRemoveSelection.Insert(AssociatedObject.SelectionStart, e.Text)
                : AssociatedObject.Text.Insert(this.AssociatedObject.CaretIndex, e.Text);
        }

        e.Handled = !ValidateText(text);
    }

    /// <summary>
    ///     PreviewKeyDown event handler
    /// </summary>
    void PreviewKeyDownHandler(object sender, KeyEventArgs e)
    {
        if (string.IsNullOrEmpty(this.EmptyValue))
            return;

        string text = null;

        // Handle the Backspace key
        if (e.Key == Key.Back)
        {
            if (!this.TreatSelectedText(out text))
            {
                if (AssociatedObject.SelectionStart > 0)
                    text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart - 1, 1);
            }
        }
        // Handle the Delete key
        else if (e.Key == Key.Delete)
        {
            // If text was selected, delete it
            if (!this.TreatSelectedText(out text) && this.AssociatedObject.Text.Length > AssociatedObject.SelectionStart)
            {
                // Otherwise delete next symbol
                text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, 1);
            }
        }

        if (text == string.Empty)
        {
            this.AssociatedObject.Text = this.EmptyValue;
            if (e.Key == Key.Back)
                AssociatedObject.SelectionStart++;
            e.Handled = true;
        }
    }

    private void PastingHandler(object sender, DataObjectPastingEventArgs e)
    {
        if (e.DataObject.GetDataPresent(DataFormats.Text))
        {
            string text = Convert.ToString(e.DataObject.GetData(DataFormats.Text));

            if (!ValidateText(text))
                e.CancelCommand();
        }
        else
            e.CancelCommand();
    }
    #endregion Event handlers [PRIVATE] -----------------------------------

    #region Auxiliary methods [PRIVATE] -----------------------------------

    /// <summary>
    ///     Validate certain text by our regular expression and text length conditions
    /// </summary>
    /// <param name="text"> Text for validation </param>
    /// <returns> True - valid, False - invalid </returns>
    private bool ValidateText(string text)
    {
        return (new Regex(this.RegularExpression, RegexOptions.IgnoreCase)).IsMatch(text) && (MaxLength == int.MinValue || text.Length <= MaxLength);
    }

    /// <summary>
    ///     Handle text selection
    /// </summary>
    /// <returns>true if the character was successfully removed; otherwise, false. </returns>
    private bool TreatSelectedText(out string text)
    {
        text = null;
        if (AssociatedObject.SelectionLength <= 0) 
            return false;

        var length = this.AssociatedObject.Text.Length;
        if (AssociatedObject.SelectionStart >= length)
            return true;

        if (AssociatedObject.SelectionStart + AssociatedObject.SelectionLength >= length)
            AssociatedObject.SelectionLength = length - AssociatedObject.SelectionStart;

        text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, AssociatedObject.SelectionLength);
        return true;
    }
    #endregion Auxiliary methods [PRIVATE] --------------------------------
}

사용법은 매우 간단합니다.

<i:Interaction.Behaviors>
    <behaviours:TextBoxInputRegExBehaviour RegularExpression="^\d+$" MaxLength="9" EmptyValue="0" />
</i:Interaction.Behaviors>

1
이 솔루션은 훨씬 좋습니다. 그러나 당신은 작은 실수를 저질렀습니다 : MaxLength조건을 설정하지 않으면 새로운 텍스트를 테스트 할 때 (this.MaxLength == 0 || text.Length <= this.MaxLength)항상 조건이 반환 false됩니다. 의 기본값으로 (this.MaxLength == int.MinValue || text.Length <= this.MaxLength)설정했기 때문에 더 좋습니다 . int.MinValueMaxLength
Christoph Meißner

1
@Christoph에게 감사합니다. 네 맞습니다. 내 답변을 수정했습니다.
Alex Klaus

@AlexKlaus 이것은 UpdateSourceTrigger=PropertyChanged바인딩에 추가 할 때까지 훌륭하게 작동합니다 . 를 변경할 때이 코드를 작동시키는 방법 UpdateSourceTriggerPropertyChanged무엇입니까? 이 코드를 공유해 주셔서 감사합니다.
Junior

32

다음은 MVVM을 사용하여 매우 간단하고 쉬운 방법입니다.

텍스트 상자를 뷰 모델의 정수 속성과 바인딩하면 보석처럼 작동합니다. 텍스트 상자에 정수가 아닌 문자를 입력하면 유효성 검사가 표시됩니다.

XAML 코드 :

<TextBox x:Name="contactNoTxtBox"  Text="{Binding contactNo}" />

모델 코드보기 :

private long _contactNo;
public long contactNo
{
    get { return _contactNo; }
    set
    {
        if (value == _contactNo)
            return;
        _contactNo = value;
        OnPropertyChanged();
    }
}

그러나 질문에는 "숫자와 소수점을 허용하려고합니다"가 포함되어 있습니다. 이 답변에 소수점이 허용됩니까?
Peter Mortensen

로 변경 long을 시도했지만 float즉시 유효성 검사를 수행해도 제대로 작동하지 않았습니다. UpdateSourceTrigger="PropertyChanged"바인딩에 추가 했으므로 각 문자를 입력 할 때 유효성 검사를 수행하고 더 이상 '.'를 입력 할 수 없었습니다. 텍스트 상자에 잘못된 문자가 없으면 ( "1x.234"를 입력 한 다음 'x'를 삭제해야 함) 이 모드에서는 약간 느립니다. 이것은 System.Number.ParseSingle()작업을 수행하는 데 사용 되는 것처럼 보이 므로 다양한 표기법을 받아들입니다.
fadden

@wolle은 유효성 검사의 작동 방식을 설명하지 않기 때문에 투표에 참여하지 않을 수 있습니다.
Paul McCarthy

26

텍스트가 변경 될 때 데이터가 숫자인지 여부를 확인하고 데이터가 숫자 인 경우 처리를 계속할 수 있는지 확인하고 그렇지 않은 경우 해당 필드에 숫자 데이터 만 허용하도록 사용자에게 프롬프트하도록 유효성 검사 규칙을 추가하십시오.

Windows Presentation Foundation의 유효성 검사에서 자세한 내용을 확인하십시오.


6
이것은 실제로 SO 표준에 대한 답이 아닙니다.
Robert Baker

이것은 .net 방식으로 보입니다.
Telemat

1
것입니다 올바른 답 : 검증은 viene 모델 또는 모델 수준에서해야한다. 또한 숫자 형식에 바인딩 double하면 표준 유효성 검사가 이미 제공됩니다.

24

확장 WPF 툴킷에는 NumericUpDown이 있습니다. 여기에 이미지 설명을 입력하십시오


이 컨트롤을 시도했지만 UpdateSourceTrigger = PropertyChanged와 함께 스피너를 사용할 때 문제가 발생하며 일반적으로 과학 표기법을 입력하기가 어렵습니다.
Menno Deij-반 Rijswijk

5
통지하시기 바랍니다 NumericUpDown지금은 사용되지 않습니다. 당신이 사용할 수있는 DecimalUpDown업데이트 된 툴킷에서 WPF 툴킷 ™ 커뮤니티 에디션 확장
itsho

20

단순히 유효성 검사 규칙을 구현하여 TextBox에 적용 할 수도 있습니다.

  <TextBox>
    <TextBox.Text>
      <Binding Path="OnyDigitInput" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
        <Binding.ValidationRules>
          <conv:OnlyDigitsValidationRule />
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>

다음과 같은 규칙을 구현하면 (다른 답변에서 제안한 것과 동일한 정규식 사용) :

public class OnlyDigitsValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        var validationResult = new ValidationResult(true, null);

        if(value != null)
        {
            if (!string.IsNullOrEmpty(value.ToString()))
            {
                var regex = new Regex("[^0-9.-]+"); //regex that matches disallowed text
                var parsingOk = !regex.IsMatch(value.ToString());
                if (!parsingOk)
                {
                    validationResult = new ValidationResult(false, "Illegal Characters, Please Enter Numeric Value");
                }
            }
        }

        return validationResult;
    }
}

십진수를 입력하려면 텍스트가 "."로 끝날 때 "유효"를 반환하지 마십시오. 를 참조하십시오 stackoverflow.com/a/27838893/417939
YantingChen

14

여기에 Ray의 답변에서 영감을 얻은 간단한 솔루션이 있습니다. 이것은 모든 형태의 숫자를 식별하기에 충분해야합니다.

양수, 정수 값 또는 최대 소수점 이하 자릿수까지 정확한 값만 원하는 경우에도이 솔루션을 쉽게 수정할 수 있습니다.


Ray의 답변 에서 제안한 것처럼 먼저 PreviewTextInput이벤트를 추가해야합니다 .

<TextBox PreviewTextInput="TextBox_OnPreviewTextInput"/>

그런 다음 코드 뒤에 다음을 입력하십시오.

private void TextBox_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
    var textBox = sender as TextBox;
    // Use SelectionStart property to find the caret position.
    // Insert the previewed text into the existing text in the textbox.
    var fullText = textBox.Text.Insert(textBox.SelectionStart, e.Text);

    double val;
    // If parsing is successful, set Handled to false
    e.Handled = !double.TryParse(fullText, out val);
}

4
나는이 답변이 간단하고 효과적입니다.
Pulle

신과 단순하지만 공간을 허용한다는 못생긴
Momo

2
그래도 누군가가 텍스트 상자에 문자열을 붙여 넣을 수 있습니다
FCin

8

숫자 키패드 숫자와 백 스페이스를 허용했습니다.

    private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        int key = (int)e.Key;

        e.Handled = !(key >= 34 && key <= 43 || 
                      key >= 74 && key <= 83 || 
                      key == 2);
    }

8
Magic Numbers 대신 enum 값을 사용하는 것이 좋습니다 .var keyEnum = (System.Windows.Input.Key) e.Key; e.Handled = !(keyEnum >= System.Windows.Input.Key.D0 && keyEnum <= System.Windows.Input.Key.D9 || keyEnum >= System.Windows.Input.Key.NumPad0 && keyEnum <= System.Windows.Input.Key.NumPad9 || keyEnum == System.Windows.Input.Key.Back);
itsho

7

나는 다음과 같이 가정 할 것이다.

  1. 숫자 입력을 허용하려는 TextBox의 Text 속성은 처음에 유효한 숫자 값 (예 : 2.7172)으로 설정되어 있습니다.

  2. 텍스트 상자는 기본 창의 자식입니다

  3. 메인 윈도우는 Window1 클래스입니다.

  4. TextBox 이름은 숫자 TB입니다

기본 아이디어 :

  1. 추가 : private string previousText;기본 창 클래스 (Window1)

  2. 추가 : previousText = numericTB.Text;기본 창 생성자

  3. numericTB.TextChanged 이벤트에 대한 핸들러를 다음과 같이 작성하십시오.

    private void numericTB_TextChanged(object sender, TextChangedEventArgs e)
    {
        double num = 0;
        bool success = double.TryParse(((TextBox)sender).Text, out num);
        if (success & num >= 0)
            previousText = ((TextBox)sender).Text;
        else
            ((TextBox)sender).Text = previousText;
    }

이렇게하면 previousText를 유효한 한 계속해서 numericTB.Text로 설정하고, 사용자가 원하지 않는 것을 쓰면 numericTB.Text를 마지막 유효한 값으로 설정합니다. 물론 이것은 단지 기본 아이디어 일 뿐이며 "바보 증거"가 아니라 "바보 저항"입니다. 예를 들어 사용자가 공백으로 엉망인 경우는 처리하지 않습니다. 그래서 여기에 "바보 증거"라고 생각하는 완벽한 솔루션이 있습니다. 틀린 경우 알려주세요.

  1. Window1.xaml 파일의 내용 :

    <Window x:Class="IdiotProofNumericTextBox.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <TextBox Height="30" Width="100" Name="numericTB" TextChanged="numericTB_TextChanged"/>
        </Grid>
    </Window>
  2. Window.xaml.cs 파일의 내용 :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace IdiotProofNumericTextBox
    {
        public partial class Window1 : Window
        {
            private string previousText;
    
            public Window1()
            {
                InitializeComponent();
                previousText = numericTB.Text;
            }
    
            private void numericTB_TextChanged(object sender, TextChangedEventArgs e)
            {
                if (string.IsNullOrEmpty(((TextBox)sender).Text))
                    previousText = "";
                else
                {
                    double num = 0;
                    bool success = double.TryParse(((TextBox)sender).Text, out num);
                    if (success & num >= 0)
                    {
                        ((TextBox)sender).Text.Trim();
                        previousText = ((TextBox)sender).Text;
                    }
                    else
                    {
                        ((TextBox)sender).Text = previousText;
                        ((TextBox)sender).SelectionStart = ((TextBox)sender).Text.Length;
                    }
                }
            }
        }
    }

그리고 그게 다야. 많은 TextBox가있는 경우 TextBox에서 상속되는 CustomControl을 만드는 것이 좋습니다. 따라서 previousText 및 numericTB_TextChanged를 별도의 파일로 래핑 할 수 있습니다.


와우 대단해! 앞면에 음수 기호를 어떻게 허용합니까?
theNoobGuy

6

이것은 필요한 유일한 코드입니다.

void MyTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    e.Handled = new Regex("[^0-9]+").IsMatch(e.Text);
}

텍스트 상자에 숫자 만 입력 할 수 있습니다.

소수점 또는 빼기 기호를 허용하려면 정규식을로 변경하면됩니다 [^0-9.-]+.


1
하나의 작은 nitpick을 제외하고 매우 좋은 해결책 : PreviewTextInput 이벤트를 트리거하지 않기 때문에 공백 입력을 막지 않습니다.
Tim Pohlmann

백 스페이스는이를 발생시키지 않습니다.
Winger Sendon

6

기본 기능을 수행하기 위해 많은 코드를 작성하지 않으려면 (사람들이 왜 긴 메서드를 만드는지 모르겠습니다) 다음과 같이하면됩니다.

  1. 네임 스페이스 추가 :

    using System.Text.RegularExpressions;
  2. XAML에서 TextChanged 속성을 설정하십시오.

    <TextBox x:Name="txt1" TextChanged="txt1_TextChanged"/>
  3. txt1_TextChanged 메소드 아래의 WPF에서 다음을 추가하십시오 Regex.Replace.

    private void txt1_TextChanged(object sender, TextChangedEventArgs e)
    {
        txt1.Text = Regex.Replace(txt1.Text, "[^0-9]+", "");
    }

2
Behavior 또는 AttachedProperty를 사용하는 것이 훨씬 깔끔합니다. 모든보기 / 모든 텍스트 상자에 대해 코드 숨김 fiddeling 없음
루포 경

당근이 텍스트 상자의 앞쪽 위치로 점프 할 때 작동하지만 추악합니다
Momo

6

다른 접근 방식은 첨부 된 동작을 사용하는 것 입니다. 프로젝트 전체의 텍스트 상자에서 사용할 수있는 사용자 정의 TextBoxHelper 클래스를 구현 했습니다. 이 목적으로 모든 텍스트 상자 및 모든 개별 XAML 파일의 이벤트를 구독하면 시간이 많이 걸릴 수 있다고 생각했기 때문입니다.

내가 구현 한 TextBoxHelper 클래스에는 다음과 같은 기능이 있습니다.

  • Double , Int , UintNatural 형식의 숫자 만 필터링하고 허용
  • 단지 필터링 및 수용 또는 홀수 번호를
  • 숫자 텍스트 상자에 유효하지 않은 텍스트를 붙여 넣지 않도록 붙여 넣기 이벤트 처리기 처리
  • TextBoxes TextChanged 이벤트를 구독하여 유효하지 않은 데이터를 마지막 샷으로 방지하는 데 사용할 기본값을 설정할 수 있습니다

TextBoxHelper 클래스의 구현은 다음과 같습니다.

public static class TextBoxHelper
{
    #region Enum Declarations

    public enum NumericFormat
    {
        Double,
        Int,
        Uint,
        Natural
    }

    public enum EvenOddConstraint
    {
        All,
        OnlyEven,
        OnlyOdd
    }

    #endregion

    #region Dependency Properties & CLR Wrappers

    public static readonly DependencyProperty OnlyNumericProperty =
        DependencyProperty.RegisterAttached("OnlyNumeric", typeof(NumericFormat?), typeof(TextBoxHelper),
            new PropertyMetadata(null, DependencyPropertiesChanged));
    public static void SetOnlyNumeric(TextBox element, NumericFormat value) =>
        element.SetValue(OnlyNumericProperty, value);
    public static NumericFormat GetOnlyNumeric(TextBox element) =>
        (NumericFormat) element.GetValue(OnlyNumericProperty);


    public static readonly DependencyProperty DefaultValueProperty =
        DependencyProperty.RegisterAttached("DefaultValue", typeof(string), typeof(TextBoxHelper),
            new PropertyMetadata(null, DependencyPropertiesChanged));
    public static void SetDefaultValue(TextBox element, string value) =>
        element.SetValue(DefaultValueProperty, value);
    public static string GetDefaultValue(TextBox element) => (string) element.GetValue(DefaultValueProperty);


    public static readonly DependencyProperty EvenOddConstraintProperty =
        DependencyProperty.RegisterAttached("EvenOddConstraint", typeof(EvenOddConstraint), typeof(TextBoxHelper),
            new PropertyMetadata(EvenOddConstraint.All, DependencyPropertiesChanged));
    public static void SetEvenOddConstraint(TextBox element, EvenOddConstraint value) =>
        element.SetValue(EvenOddConstraintProperty, value);
    public static EvenOddConstraint GetEvenOddConstraint(TextBox element) =>
        (EvenOddConstraint)element.GetValue(EvenOddConstraintProperty);

    #endregion

    #region Dependency Properties Methods

    private static void DependencyPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is TextBox textBox))
            throw new Exception("Attached property must be used with TextBox.");

        switch (e.Property.Name)
        {
            case "OnlyNumeric":
            {
                var castedValue = (NumericFormat?) e.NewValue;

                if (castedValue.HasValue)
                {
                    textBox.PreviewTextInput += TextBox_PreviewTextInput;
                    DataObject.AddPastingHandler(textBox, TextBox_PasteEventHandler);
                }
                else
                {
                    textBox.PreviewTextInput -= TextBox_PreviewTextInput;
                    DataObject.RemovePastingHandler(textBox, TextBox_PasteEventHandler);
                }

                break;
            }

            case "DefaultValue":
            {
                var castedValue = (string) e.NewValue;

                if (castedValue != null)
                {
                    textBox.TextChanged += TextBox_TextChanged;
                }
                else
                {
                    textBox.TextChanged -= TextBox_TextChanged;
                }

                break;
            }
        }
    }

    #endregion

    private static void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        var textBox = (TextBox)sender;

        string newText;

        if (textBox.SelectionLength == 0)
        {
            newText = textBox.Text.Insert(textBox.SelectionStart, e.Text);
        }
        else
        {
            var textAfterDelete = textBox.Text.Remove(textBox.SelectionStart, textBox.SelectionLength);

            newText = textAfterDelete.Insert(textBox.SelectionStart, e.Text);
        }

        var evenOddConstraint = GetEvenOddConstraint(textBox);

        switch (GetOnlyNumeric(textBox))
        {
            case NumericFormat.Double:
            {
                if (double.TryParse(newText, out double number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;
                    }
                }
                else
                    e.Handled = true;

                break;
            }

            case NumericFormat.Int:
            {
                if (int.TryParse(newText, out int number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;
                    }
                }
                else
                    e.Handled = true;

                break;
            }

            case NumericFormat.Uint:
            {
                if (uint.TryParse(newText, out uint number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;
                    }
                }
                else
                    e.Handled = true;

                break;
            }

            case NumericFormat.Natural:
            {
                if (uint.TryParse(newText, out uint number))
                {
                    if (number == 0)
                        e.Handled = true;
                    else
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;

                                break;
                        }
                    }
                }
                else
                    e.Handled = true;

                break;
            }
        }
    }

    private static void TextBox_PasteEventHandler(object sender, DataObjectPastingEventArgs e)
    {
        var textBox = (TextBox)sender;

        if (e.DataObject.GetDataPresent(typeof(string)))
        {
            var clipboardText = (string) e.DataObject.GetData(typeof(string));

            var newText = textBox.Text.Insert(textBox.SelectionStart, clipboardText);

            var evenOddConstraint = GetEvenOddConstraint(textBox);

            switch (GetOnlyNumeric(textBox))
            {
                case NumericFormat.Double:
                {
                    if (double.TryParse(newText, out double number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.CancelCommand();

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.CancelCommand();

                                break;
                        }
                    }
                    else
                        e.CancelCommand();

                    break;
                }

                case NumericFormat.Int:
                {
                    if (int.TryParse(newText, out int number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.CancelCommand();

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.CancelCommand();


                                break;
                        }
                    }
                    else
                        e.CancelCommand();

                    break;
                }

                case NumericFormat.Uint:
                {
                    if (uint.TryParse(newText, out uint number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.CancelCommand();

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.CancelCommand();


                                break;
                        }
                    }
                    else
                        e.CancelCommand();

                    break;
                }

                case NumericFormat.Natural:
                {
                    if (uint.TryParse(newText, out uint number))
                    {
                        if (number == 0)
                            e.CancelCommand();
                        else
                        {
                            switch (evenOddConstraint)
                            {
                                case EvenOddConstraint.OnlyEven:

                                    if (number % 2 != 0)
                                        e.CancelCommand();

                                    break;

                                case EvenOddConstraint.OnlyOdd:

                                    if (number % 2 == 0)
                                        e.CancelCommand();

                                    break;
                            }
                        }
                    }
                    else
                    {
                        e.CancelCommand();
                    }

                    break;
                }
            }
        }
        else
        {
            e.CancelCommand();
        }
    }

    private static void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        var textBox = (TextBox)sender;

        var defaultValue = GetDefaultValue(textBox);

        var evenOddConstraint = GetEvenOddConstraint(textBox);

        switch (GetOnlyNumeric(textBox))
        {
            case NumericFormat.Double:
            {
                if (double.TryParse(textBox.Text, out double number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                textBox.Text = defaultValue;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                textBox.Text = defaultValue;

                            break;
                    }
                }
                else
                    textBox.Text = defaultValue;

                break;
            }

            case NumericFormat.Int:
            {
                if (int.TryParse(textBox.Text, out int number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                textBox.Text = defaultValue;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                textBox.Text = defaultValue;

                            break;
                    }
                }
                else
                    textBox.Text = defaultValue;

                break;
            }

            case NumericFormat.Uint:
            {
                if (uint.TryParse(textBox.Text, out uint number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                textBox.Text = defaultValue;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                textBox.Text = defaultValue;

                            break;
                    }
                }
                else
                    textBox.Text = defaultValue;

                break;
            }

            case NumericFormat.Natural:
            {
                if (uint.TryParse(textBox.Text, out uint number))
                {
                    if(number == 0)
                        textBox.Text = defaultValue;
                    else
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    textBox.Text = defaultValue;

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    textBox.Text = defaultValue;

                                break;
                        }
                    }
                }
                else
                {
                    textBox.Text = defaultValue;
                }

                break;
            }
        }
    }
}

다음은 쉬운 사용법의 예입니다.

<TextBox viewHelpers:TextBoxHelper.OnlyNumeric="Double"
         viewHelpers:TextBoxHelper.DefaultValue="1"/>

또는

<TextBox viewHelpers:TextBoxHelper.OnlyNumeric="Natural"
         viewHelpers:TextBoxHelper.DefaultValue="3"
         viewHelpers:TextBoxHelper.EvenOddConstraint="OnlyOdd"/>

참고 그 viewHelpers의 xmlns 별칭 내 TextBoxHelper 상주.

이 구현으로 다른 사람의 작업이 쉬워지기를 바랍니다. :)


1
이것은 DataTemplate 내에서 텍스트 상자를 사용할 때 좋습니다. 감사합니다!
NucS

3
큰 대답이지만 귀하의 방법을 읽기가 어렵습니다. 아마도 당신은 그것들을 더 작은 것으로 나누어야 할 것입니다. 참조 당신을위한 방법의 이상적인 길이는 무엇입니까?
Anthony

건설적인 피드백 @Anthony 주셔서 감사합니다
아미르 마흐디 Nassiri에게

4
e.Handled = (int)e.Key >= 43 || (int)e.Key <= 34;

텍스트 상자의 미리보기 키 다운 이벤트에서.


3
백 스페이스를 허용하지 않습니다.
sventevit

2
백 스페이스는 2, 탭은 3
Daniel

6
-1 내 경험상 이런 종류의 똑똑한 트릭은 결국 다른 주석가들이 지적했듯이 결국 엉덩이를 물게하기 때문입니다.
DonkeyMaster

왼쪽 화살표는 23, 오른쪽 화살표는 25입니다.
Aaron

4
PreviewTextInput += (s, e) =>
{
    e.Handled = !e.Text.All(char.IsDigit);
};

2
이 또한 점에 동의하지 않습니다 .때문에, e.Text마지막 입력 문자를 반환하고 도트가 실패합니다 IsDigit확인.
Anthony

4

XAML 파일에서 정수와 10 진수 만 사용하여 이러한 유형의 문제에 대한 빠르고 간단한 구현을 원하는 경우 XAML 파일에 PreviewTextInput속성을 추가 한 TextBox다음 xaml.cs 파일에서 사용하십시오.

private void Text_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    e.Handled = !char.IsDigit(e.Text.Last()) && !e.Text.Last() == '.';
}

다른 사람들이 언급했듯이 과학적 표기법으로 무언가를하고 있지 않는 한 매번 전체 문자열을 계속 확인하는 것은 불필요합니다 ( 'e'와 같은 특정 문자를 추가하는 경우 기호 / 문자를 추가하는 간단한 정규 표현식은 정말 간단하고 다른 답변에 설명되어 있습니다). 그러나 간단한 부동 소수점 값의 경우이 솔루션으로 충분합니다.

람다 식의 원 라이너로 작성 :

private void Text_PreviewTextInput(object sender, TextCompositionEventArgs e) => e.Handled = !char.IsDigit(e.Text.Last() && !e.Text.Last() == '.');

3

텍스트 상자 변경 이벤트에 대한 유효성 검사를 수행 할 수 있습니다. 다음 구현은 숫자 및 소수점 하나 이외의 키 누르기 입력을 방지합니다.

private void textBoxNumeric_TextChanged(object sender, TextChangedEventArgs e) 
{         
      TextBox textBox = sender as TextBox;         
      Int32 selectionStart = textBox.SelectionStart;         
      Int32 selectionLength = textBox.SelectionLength;         
      String newText = String.Empty;         
      int count = 0;         
      foreach (Char c in textBox.Text.ToCharArray())         
      {             
         if (Char.IsDigit(c) || Char.IsControl(c) || (c == '.' && count == 0))             
         {                 
            newText += c;                 
            if (c == '.')                     
              count += 1;             
         }         
     }         
     textBox.Text = newText;         
     textBox.SelectionStart = selectionStart <= textBox.Text.Length ? selectionStart :        textBox.Text.Length;     
} 

3

이건 어때요? 나를 위해 잘 작동합니다. 가장자리 케이스를 놓치지 않았기를 바랍니다 ...

MyTextBox.PreviewTextInput += (sender, args) =>
{
    if (!int.TryParse(args.Text, out _))
    {
        args.Handled = true;
    }
};

DataObject.AddPastingHandler(MyTextBox, (sender, args) =>
{
    var isUnicodeText = args.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true);
    if (!isUnicodeText)
    {
        args.CancelCommand();
    }

    var data = args.SourceDataObject.GetData(DataFormats.UnicodeText) as string;
    if (!int.TryParse(data, out _))
    {
        args.CancelCommand();
    }
});

2

Windows Forms에서는 쉬웠습니다. KeyPress에 이벤트를 추가하면 모든 것이 쉽게 작동합니다. 그러나 WPF에는 해당 이벤트가 없습니다. 그러나 훨씬 쉬운 방법이 있습니다.

WPF TextBox에는 모든 것에 대해 일반적인 TextChanged 이벤트가 있습니다. 붙여 넣기, 타이핑 및 마음에 떠오르는 모든 것이 포함됩니다.

따라서 다음과 같이 할 수 있습니다.

XAML :

<TextBox name="txtBox1" ... TextChanged="TextBox_TextChanged"/>

코드 비헤이비어 :

private void TextBox_TextChanged(object sender, TextChangedEventArgs e) {
    string s = Regex.Replace(((TextBox)sender).Text, @"[^\d.]", "");
    ((TextBox)sender).Text = s;
}

이것은 또한 허용 .당신이 그것을 원하지 않는 경우, 단지에서 제거 regex할 문 @[^\d].

참고 :이 이벤트는 sender객체의 Text를 사용하므로 많은 TextBox에서 사용할 수 있습니다 . 이벤트를 한 번만 작성하고 여러 TextBox에 사용할 수 있습니다.


2

이제이 질문 에 허용 된 답변 이 있음을 알고 있지만 개인적으로 조금 혼란스럽고 그보다 쉬워야한다고 생각합니다. 따라서 가능한 한 최선을 다하는 방법을 보여 드리겠습니다.

에서 윈도우 폼 ,라는 이벤트있어 KeyPress작업의 이런 종류의 완벽 좋다. 그러나 WPF 에는 존재하지 않으므로 대신 PreviewTextInput이벤트를 사용합니다 . 또한 유효성 검사를 위해 a foreach를 사용 하여 루프를 반복 하고 조건 textbox.Text일치 하는지 검사 할 수 있다고 생각 합니다 .) 그러나 정직하게 이것은 정규 표현식 입니다.

우리 가 거룩한 코드 로 뛰어 들기 전에 한 가지 더 . 이벤트가 시작 되려면 두 가지 작업을 수행 할 수 있습니다.

  1. XAML을 사용하여 호출 할 함수를 프로그램에 알리십시오. <PreviewTextInput="textBox_PreviewTextInput/>
  2. Loaded(textBox가있는) 양식 의 경우에 수행하십시오. textBox.PreviewTextInput += onlyNumeric;

이 같은 상황에서, 당신은 대부분 동일한 조건 (적용해야 할 것이기 때문에 두 번째 방법이 더 나은 생각 regex보다 하나)을 TextBox하고 자신을 반복하고 싶지 않아! .

마지막으로 수행 방법은 다음과 같습니다.

private void onlyNumeric(object sender, TextCompositionEventArgs e)
{
    string onlyNumeric = @"^([0-9]+(.[0-9]+)?)$";
    Regex regex = new Regex(onlyNumeric);
    e.Handled = !regex.IsMatch(e.Text);
}

2

여기 내 버전이 있습니다. ValidatingTextBox"유효하지 않은"수행 된 작업을 취소 하는 기본 클래스를 기반으로합니다 . 붙여 넣기, 잘라 내기, 삭제, 백 스페이스, +,-등을 지원합니다.

32 비트 정수의 경우 int와 비교하는 Int32TextBox 클래스가 있습니다. 또한 부동 소수점 유효성 검사 클래스를 추가했습니다.

public class ValidatingTextBox : TextBox
{
    private bool _inEvents;
    private string _textBefore;
    private int _selectionStart;
    private int _selectionLength;

    public event EventHandler<ValidateTextEventArgs> ValidateText;

    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        if (_inEvents)
            return;

        _selectionStart = SelectionStart;
        _selectionLength = SelectionLength;
        _textBefore = Text;
    }

    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        if (_inEvents)
            return;

        _inEvents = true;
        var ev = new ValidateTextEventArgs(Text);
        OnValidateText(this, ev);
        if (ev.Cancel)
        {
            Text = _textBefore;
            SelectionStart = _selectionStart;
            SelectionLength = _selectionLength;
        }
        _inEvents = false;
    }

    protected virtual void OnValidateText(object sender, ValidateTextEventArgs e) => ValidateText?.Invoke(this, e);
}

public class ValidateTextEventArgs : CancelEventArgs
{
    public ValidateTextEventArgs(string text) => Text = text;

    public string Text { get; }
}

public class Int32TextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !int.TryParse(e.Text, out var value);
}

public class Int64TextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !long.TryParse(e.Text, out var value);
}

public class DoubleTextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !double.TryParse(e.Text, out var value);
}

public class SingleTextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !float.TryParse(e.Text, out var value);
}

public class DecimalTextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !decimal.TryParse(e.Text, out var value);
}

참고 1 : WPF 바인딩을 사용하는 경우 바인딩 된 속성 유형에 맞는 클래스를 사용해야합니다. 그렇지 않으면 이상한 결과가 발생할 수 있습니다.

참고 2 : WPF 바인딩과 함께 부동 소수점 클래스를 사용하는 경우 바인딩에서 현재 culture를 사용하여 사용한 TryParse 메서드와 일치하는지 확인하십시오.



1

사용하다:

Private Sub DetailTextBox_PreviewTextInput( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Input.TextCompositionEventArgs) _
  Handles DetailTextBox.PreviewTextInput

    If _IsANumber Then
        If Not Char.IsNumber(e.Text) Then
            e.Handled = True
        End If
    End If
End Sub

순서대로 설명하겠습니다.
Peter Mortensen

1

나는 작업중 인 간단한 프로젝트를 위해 언 바운드 상자로 작업하고 있었으므로 표준 바인딩 방식을 사용할 수 없었습니다. 결과적으로 기존 TextBox 컨트롤을 확장하여 다른 사람들이 쉽게 찾을 수있는 간단한 해킹을 만들었습니다.

namespace MyApplication.InterfaceSupport
{
    public class NumericTextBox : TextBox
    {


        public NumericTextBox() : base()
        {
            TextChanged += OnTextChanged;
        }


        public void OnTextChanged(object sender, TextChangedEventArgs changed)
        {
            if (!String.IsNullOrWhiteSpace(Text))
            {
                try
                {
                    int value = Convert.ToInt32(Text);
                }
                catch (Exception e)
                {
                    MessageBox.Show(String.Format("{0} only accepts numeric input.", Name));
                    Text = "";
                }
            }
        }


        public int? Value
        {
            set
            {
                if (value != null)
                {
                    this.Text = value.ToString();
                }
                else 
                    Text = "";
            }
            get
            {
                try
                {
                    return Convert.ToInt32(this.Text);
                }
                catch (Exception ef)
                {
                    // Not numeric.
                }
                return null;
            }
        }
    }
}

부동 유형의 경우 부동 유형으로 구문 분석하고 싶을 것입니다. 동일한 원칙이 적용됩니다.

그런 다음 XAML 파일에 관련 네임 스페이스를 포함해야합니다.

<UserControl x:Class="MyApplication.UserControls.UnParameterisedControl"
             [ Snip ]
             xmlns:interfaceSupport="clr-namespace:MyApplication.InterfaceSupport"
             >

그런 다음 일반 컨트롤로 사용할 수 있습니다.

<interfaceSupport:NumericTextBox Height="23" HorizontalAlignment="Left" Margin="168,51,0,0" x:Name="NumericBox" VerticalAlignment="Top" Width="120" >

1

여기에 몇 가지 솔루션을 사용한 후 MVVM 설정에 적합한 자체 솔루션을 개발했습니다. 사용자가 여전히 잘못된 문자를 입력 할 수 있다는 점에서 다른 것보다 역동적이지는 않지만 버튼을 눌러 무언가를 수행하는 것을 차단합니다. 이것은 작업을 수행 할 수 없을 때 버튼을 흐리게 표시한다는 주제와 잘 어울립니다.

나는이 TextBox사용자가 문서 페이지의 번호를 인쇄 할 입력해야합니다 :

<TextBox Text="{Binding NumberPagesToPrint, UpdateSourceTrigger=PropertyChanged}"/>

...이 바인딩 속성으로 :

private string _numberPagesToPrint;
public string NumberPagesToPrint
{
    get { return _numberPagesToPrint; }
    set
    {
        if (_numberPagesToPrint == value)
        {
            return;
        }

        _numberPagesToPrint = value;
        OnPropertyChanged("NumberPagesToPrint");
    }
}

버튼도 있습니다.

<Button Template="{DynamicResource CustomButton_Flat}" Content="Set"
        Command="{Binding SetNumberPagesCommand}"/>

...이 명령 바인딩으로 :

private RelayCommand _setNumberPagesCommand;
public ICommand SetNumberPagesCommand
{
    get
    {
        if (_setNumberPagesCommand == null)
        {
            int num;
            _setNumberPagesCommand = new RelayCommand(param => SetNumberOfPages(),
                () => Int32.TryParse(NumberPagesToPrint, out num));
        }

        return _setNumberPagesCommand;
    }
}

그리고의 방법이 SetNumberOfPages()있지만이 주제에서는 중요하지 않습니다. View의 코드 숨김 파일에 코드를 추가 할 필요가 없으므로 Command속성을 사용하여 동작을 제어 할 수 있기 때문에 제 경우에는 잘 작동 합니다.



1

WPF 애플리케이션에서 TextChanged이벤트 를 처리하여이를 처리 할 수 ​​있습니다 .

void arsDigitTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
    Regex regex = new Regex("[^0-9]+");
    bool handle = regex.IsMatch(this.Text);
    if (handle)
    {
        StringBuilder dd = new StringBuilder();
        int i = -1;
        int cursor = -1;
        foreach (char item in this.Text)
        {
            i++;
            if (char.IsDigit(item))
                dd.Append(item);
            else if(cursor == -1)
                cursor = i;
        }
        this.Text = dd.ToString();

        if (i == -1)
            this.SelectionStart = this.Text.Length;
        else
            this.SelectionStart = cursor;
    }
}

1

텍스트 필드에서 소켓 포트 등과 같은 부호없는 숫자 만 허용하려는 개발자의 경우 :

WPF

<TextBox PreviewTextInput="Port_PreviewTextInput" MaxLines="1"/>

씨#

private void Port_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    e.Handled = !int.TryParse(e.Text, out int x);
}

2
실제로 소켓 포트 필드와 함께이 방법을 사용하려면주의하십시오. 정수가보다 작거나 같은지 확인해야 65535합니다. 크면 유효한 포트가 아닙니다. 또한, 설정 TextBox.MaxLength하는 것은 5도움이 될 프로그램 또는 XAML에서 중 .
Beyondo

0

이것은 숫자와 소수점을 허용하는 WPF 텍스트 상자를 얻는 데 사용하는 것입니다.

class numericTextBox : TextBox
{
    protected override void OnKeyDown(KeyEventArgs e)
    {
        bool b = false;
        switch (e.Key)
        {
            case Key.Back: b = true; break;
            case Key.D0: b = true; break;
            case Key.D1: b = true; break;
            case Key.D2: b = true; break;
            case Key.D3: b = true; break;
            case Key.D4: b = true; break;
            case Key.D5: b = true; break;
            case Key.D6: b = true; break;
            case Key.D7: b = true; break;
            case Key.D8: b = true; break;
            case Key.D9: b = true; break;
            case Key.OemPeriod: b = true; break;
        }
        if (b == false)
        {
            e.Handled = true;
        }
        base.OnKeyDown(e);
    }
}

코드를 새 클래스 파일에 넣고 추가하십시오.

using System.Windows.Controls;
using System.Windows.Input;

파일 맨 위에 솔루션을 빌드하십시오. 그러면 numericTextBox 컨트롤이 도구 상자 상단에 나타납니다.


1
NumberValidationTextBox 및 정규식을 사용하는 이전 MUCH 더 쉬운 솔루션을 참조하십시오. 이건 말도 안돼
Scott Shaw-Smith

@ ScottShaw-Smith 아마도 받아 들여진 솔루션은 코드가 적지 만 이것보다 빠르지는 않습니다. 정규식을 사용하는 대신 많은 처리 능력이 필요한 일부 프로젝트가 항상 있습니다.
Beyondo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.