WPFで数値入力のみを受け入れるようにTextBoxを取得するにはどうすればよいですか?

2009年08月13日に質問されました。  ·  閲覧回数 455.6k回  ·  ソース

Giffyguy picture
2009年08月13日

数字と小数点を受け入れたいのですが、符号はありません。

Windowsフォーム用のNumericUpDownコントロールを使用したサンプルと、MicrosoftのNumericUpDownカスタムコントロールのこのサンプルを見てきました。 しかし、これまでのところ、NumericUpDown(WPFでサポートされているかどうかに関係なく)は、私が望む機能を提供しないようです。 私のアプリケーションが設計されている方法では、彼らの正しい心の誰もが矢印を台無しにしたいとは思わないでしょう。 私のアプリケーションのコンテキストでは、これらは実用的な意味を持ちません。

そのため、標準のWPFTextBoxが必要な文字のみを受け入れるようにする簡単な方法を探しています。 これは可能ですか? それは実用的ですか?

回答

Ray picture
2009年08月13日
434

プレビューテキスト入力イベントを追加します。 そのように: <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();
    }
}
Kishor picture
2012年10月04日
204

イベントハンドラーはテキスト入力をプレビューしています。 ここで、正規表現は、数値でない場合にのみ入力されたテキストと一致し、入力テキストボックスには作成されません。

文字のみが必要な場合は、正規表現を[^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);
}
Wil P picture
2011年11月05日
87

私はすでにここにあるもののいくつかを使用し、動作を使用してそれに独自のひねりを加えたので、このコードを大量のビュー全体に伝播する必要はありません...

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>
Alex Klaus picture
2013年07月18日
59

これは、 WilPの回答の改善されたソリューションです。 私の改善点は次のとおりです。

  • DelボタンとBackspaceボタンの動作が改善されました
  • 空の文字列が不適切な場合、 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>
Snziv Gupta picture
2017年06月16日
34

これは、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();
    }
}
Stephen Wrighton picture
2009年08月13日
28

検証ルールを追加して、テキストが変更されたときにデータが数値であるかどうかを確認し、数値である場合は処理を続行できるようにし、そうでない場合は、そのフィールドで数値データのみが受け入れられることをユーザーに求めます。

詳細については、Windows PresentationFoundationの検証をご覧ください。

Sam picture
2011年03月17日
24

Extented WPF Toolkitには次のものがあります: NumericUpDownenter image description here

goul picture
2016年09月01日
21

検証ルールを実装して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;
    }
}
Anthony picture
2018年01月04日
18

ここに、レイの答えに触発された簡単な解決策があり

このソリューションは、正の数、整数値、または小数点以下の最大桁数まで正確な値のみが必要な場合にも簡単に変更できます。


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);
}

無効な空白に、 NumberStyles追加できます:

using System.Globalization;

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, 
                                 NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, 
                                 CultureInfo.InvariantCulture,
                                 out val);
}
Hamzeh Soboh picture
2013年07月17日
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);
    }