Como obtenho um TextBox para aceitar apenas entrada numérica no WPF?

335

Estou procurando aceitar dígitos e o ponto decimal, mas nenhum sinal.

Eu olhei para exemplos usando o controle NumericUpDown para Windows Forms e este exemplo de um controle personalizado NumericUpDown da Microsoft . Mas até agora parece que o NumericUpDown (suportado ou não pelo WPF) não fornecerá a funcionalidade que eu quero. Da maneira como meu aplicativo é projetado, ninguém em sã consciência vai querer mexer nas setas. Eles não fazem nenhum sentido prático, no contexto da minha aplicação.

Então, estou procurando uma maneira simples de fazer com que um WPF TextBox padrão aceite apenas os caracteres que eu quero. Isso é possível? Isso é prático?

Giffyguy
fonte

Respostas:

418

Adicione um evento de entrada de texto de visualização. Assim: <TextBox PreviewTextInput="PreviewTextInput" />.

Em seguida, dentro desse conjunto, e.Handledse o texto não for permitido.e.Handled = !IsTextAllowed(e.Text);

Eu uso um regex simples no IsTextAllowedmétodo para ver se devo permitir o que eles digitaram. No meu caso, só quero permitir números, pontos e traços.

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

Se você deseja impedir a colagem de dados incorretos, conecte o DataObject.Pastingevento DataObject.Pasting="TextBoxPasting"como mostrado aqui (código extraído):

// 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();
    }
}
Raio
fonte
5
Seu regex não permite notação científica (1e5) se isso for importante.
Ron Warholic
14
Note-se que esta resposta só verifica o que você digita, para que pudesse entrar 3-0,3
David Sykes
153
O objetivo da resposta não era especificar o Regex perfeito, era mostrar como usar o WPF para filtrar o que alguém digita.
Raio
27
[Space] não dispara o evento PreviewTextInput.
PeterG 31/10
5
Algo como double.TryParse()provavelmente seria implementado com o mesmo número de linhas e seria mais flexível.
Thomas Weller
190

O manipulador de eventos está visualizando a entrada de texto. Aqui, uma expressão regular corresponde à entrada de texto apenas se não for um número e, em seguida, não é feita na caixa de texto de entrada.

Se você deseja apenas letras, substitua a expressão regular como [^a-zA-Z].

XAML

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

ARQUIVO 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);
}
Kishor
fonte
1
O manipulador de eventos é uma entrada de texto de visualização. Aqui, a expressão regular corresponde à entrada de texto apenas se não for um número, e não será feita na entrada da caixa de texto. Se você deseja apenas alfabetos, substitua a expressão regular como [^ a-zA-Z].
Kishor
E quanto a números, decimais e operadores?
Jason Ebersey
Por favor, deixe-me saber como usá-lo quando declara em alguma outra classe STATIC e se aplica à caixa de texto?
SHEKHAR SHETE
3
Gosto mais deste que a resposta real, curta e simples. A resposta real precisa de dois métodos para obter o mesmo resultado.
Sliver
1
@Jagd A resposta sugerida é uma melhor separação de preocupações. No entanto, você também pode definir quantas caixas de texto nesta validação. basta adicionar o PreviewTextInput = "NumberValidationTextBox". (assim como a outra resposta!)
Sliver
84

Eu usei parte do que já estava aqui e coloquei meu próprio toque nele usando um comportamento, para que eu não tenha que propagar esse código por uma tonelada de Views ...

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

Aqui está o código de visualização relevante:

<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>
Wil P
fonte
1
Inspirado por esta solução incrível, implementei algumas melhorias. Por favor, confira abaixo no tópico.
Alex Klaus
2
Oi. Eu sei que isso é um pouco tarde, mas estou tentando implementar isso, mas continuo recebendo erros. Acho que estou perdendo algumas referências. Existe algum que deve ser digitado além dos padrões depois que você criou uma classe?
Oferece
1
@ OFERTA Sim, certifique-se de incluir xmlns: interactivity = " schemas.microsoft.com/expression/2010/interactivity " na parte superior da janela do xaml.
WiteCastle 27/10/2014
A expressão agora está obsoleta. Embora essa abordagem seja limpa, ela está usando código que não está mais sendo mantido.
Robert Baker
1
Portanto, se você editar a função IsValid para retornar! ExceedsMaxLength (newText, colar) && Regex.IsMatch (String.Concat (this.AssociatedObject.Text, newText), RegularExpression); então isso avaliará a sequência inteira. Btw - adoro essa opção com os comportamentos !!
Rogala 28/01
59

Esta é uma solução aprimorada da resposta do WilP . Minhas melhorias são:

  • Comportamento aprimorado no Del e Backspace botões
  • Adicionado EmptyValuePropriedade , se a sequência vazia for inadequada
  • Corrigidos alguns erros menores
/// <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] --------------------------------
}

O uso é bem direto:

<i:Interaction.Behaviors>
    <behaviours:TextBoxInputRegExBehaviour RegularExpression="^\d+$" MaxLength="9" EmptyValue="0" />
</i:Interaction.Behaviors>
Alex Klaus
fonte
1
Esta solução é muito melhor. Mas você cometeu um pequeno erro: quando não estiver configurando, o MaxLengthseu condicionamento (this.MaxLength == 0 || text.Length <= this.MaxLength)retornará sempre falseao testar o novo texto. Isso deve ser melhor (this.MaxLength == int.MinValue || text.Length <= this.MaxLength)porque você define int.MinValuecomo valor padrão para MaxLength.
Christoph Meißner 24/02
1
Obrigado @Christoph, sim, você está certo. Eu modifiquei minha resposta.
Alex Klaus
@AlexKlaus isso funciona muito bem até eu adicionar UpdateSourceTrigger=PropertyChangedà ligação. Alguma idéia de como fazer esse código funcionar ao alterar o UpdateSourceTriggerestá definido como PropertyChanged? Obrigado por compartilhar este código.
Junior
32

Aqui está uma maneira muito simples e fácil de fazer isso usando o MVVM.

Vincule sua caixa de texto com uma propriedade inteira no modelo de exibição, e isso funcionará como uma gema ... até mostrará validação quando um não inteiro for inserido na caixa de texto.

Código XAML:

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

Ver código do modelo:

private long _contactNo;
public long contactNo
{
    get { return _contactNo; }
    set
    {
        if (value == _contactNo)
            return;
        _contactNo = value;
        OnPropertyChanged();
    }
}
Snziv Gupta
fonte
Mas a pergunta continha "Estou procurando aceitar dígitos e o ponto decimal" . O ponto decimal é aceito para esta resposta?
Peter Mortensen
Tentei mudar longpara float, mas não funcionou muito bem com a validação imediata. Eu adicionei UpdateSourceTrigger="PropertyChanged"à ligação, para que ela executasse a validação à medida que cada caractere fosse digitado e não pudesse mais digitar um '.' no TextBox, a menos que haja um caractere ilegal presente (foi necessário digitar "1x.234" e excluir o 'x'). Também parece um pouco lento neste modo. Parece ser usado System.Number.ParseSingle()para fazer o trabalho, por isso aceita uma variedade de notações.
Fadden
O @wolle provavelmente não foi votado porque não explica como a validação funciona.
Paul McCarthy
26

Inclua uma REGRA DE VALIDAÇÃO para que, quando o texto for alterado, verifique se os dados são numéricos e, se houver, permitam que o processamento continue e, caso contrário, solicita ao usuário que apenas dados numéricos sejam aceitos nesse campo.

Leia mais em Validação no Windows Presentation Foundation

Stephen Wrighton
fonte
6
Esta não é realmente uma resposta para os padrões de SO.
Robert Baker
Essa parece ser a maneira .net de fazer isso.
Telemat 15/10
1
A é a correta resposta: validação deve ser pelo modelo viene ou nível do modelo. Além disso, você pode simplesmente vincular-se a um tipo numérico doublee isso já está fornecendo uma validação padrão.
24

O Extended WPF Toolkit possui um: NumericUpDown insira a descrição da imagem aqui

Brian Lagunas
fonte
Eu tentei esse controle, mas ele apresenta problemas ao usar o controle giratório com UpdateSourceTrigger = PropertyChanged e geralmente é difícil para o usuário inserir notação científica.
Menno Deij - van Rijswijk
5
Observe que NumericUpDownagora está obsoleto. você pode usar DecimalUpDowno kit de ferramentas atualizado Extended WPF Toolkit ™ Community Edition
itsho
20

Também poderia simplesmente implementar uma regra de validação e aplicá-la ao TextBox:

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

Com a implementação da regra a seguir (usando o mesmo Regex proposto em outras respostas):

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;
    }
}
goul
fonte
Se você deseja inserir dígitos decimais, não retorne "válido" quando o Texto terminar em "." Por favor, consulte stackoverflow.com/a/27838893/417939
YantingChen
14

Aqui eu tenho uma solução simples inspirada na resposta de Ray . Isso deve ser suficiente para identificar qualquer forma de número.

Essa solução também pode ser facilmente modificada se você deseja apenas números positivos, valores inteiros ou valores precisos com um número máximo de casas decimais, etc.


Conforme sugerido na resposta de Ray , você precisa primeiro adicionar um PreviewTextInputevento:

<TextBox PreviewTextInput="TextBox_OnPreviewTextInput"/>

Em seguida, coloque o seguinte no código por trás:

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);
}
Anthony
fonte
4
Eu gosto muito desta resposta, simples e eficaz +
Pulle
deus e simples, mas sua feia que ele permite espaços
Momo
2
Isso ainda permite que alguém cole uma string na caixa de texto
FCin
8

Eu permiti números numéricos e backspace do teclado:

    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);
    }
Hamzeh Soboh
fonte
8
Eu recomendo usar os valores enum em vez de Magic Numbers :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

Vou assumir que:

  1. Seu TextBox para o qual você deseja permitir entrada numérica apenas tem sua propriedade Text definida inicialmente como um valor numérico válido (por exemplo, 2.7172).

  2. Sua caixa de texto é filha da sua janela principal

  3. Sua janela principal é da classe Window1

  4. Seu nome do TextBox é numericTB

Ideia básica:

  1. Adicione: private string previousText;à sua classe de janela principal (Window1)

  2. Adicione: previousText = numericTB.Text;ao construtor da janela principal

  3. Crie um manipulador para o evento numericTB.TextChanged para algo como isto:

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

Isso manterá a configuração previousText como numericTB.Text enquanto for válido e definir numericTB.Text como seu último valor válido se o usuário gravar algo que você não gosta. Obviamente, essa é apenas uma idéia básica, e é apenas "resistente a idiotas", não "à prova de idiotas". Ele não lida com o caso em que o usuário mexe com espaços, por exemplo. Então, aqui está uma solução completa que eu acho que é "prova de idiota", e se eu estiver errado, por favor me diga:

  1. Conteúdo do seu arquivo 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. Conteúdo do seu arquivo 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;
                    }
                }
            }
        }
    }

E é isso. Se você tiver muitos TextBoxes, recomendo criar um CustomControl que herda de TextBox, para que você possa agrupar previousText e numericTB_TextChanged em um arquivo separado.

user666535
fonte
Uau, isso é ótimo! Como eu poderia permitir um símbolo negativo na frente?
precisa saber é o seguinte
6

Este é o único código necessário:

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

Isso permite que apenas números sejam inseridos na caixa de texto.

Para permitir um ponto decimal ou sinal de menos, você pode alterar a expressão regular para [^0-9.-]+.

Danny Beckett
fonte
1
Solução muito boa, exceto por um pequeno detalhe: não impedirá que você insira espaços em branco, pois eles não acionam o evento PreviewTextInput.
Tim Pohlmann
O backspace também não é acionado.
Winger Sendon
6

Se você não quiser escrever muito código para executar uma função básica (não sei por que as pessoas fazem métodos longos), basta fazer o seguinte:

  1. Adicionar espaço para nome:

    using System.Text.RegularExpressions;
  2. No XAML, defina uma propriedade TextChanged:

    <TextBox x:Name="txt1" TextChanged="txt1_TextChanged"/>
  3. No WPF no método txt1_TextChanged, adicione Regex.Replace:

    private void txt1_TextChanged(object sender, TextChangedEventArgs e)
    {
        txt1.Text = Regex.Replace(txt1.Text, "[^0-9]+", "");
    }
iato
fonte
2
É muito mais limpo usar um Comportamento ou um AttachedProperty. No code-behind fiddeling em todas as vistas / para cada caixa de texto
Sir Rufo
Podem funcionar, mas é feio como a cenoura vai saltar na posição frontal da caixa de texto
Momo
6

Outra abordagem será usar um comportamento anexado; implementei minha classe TextBoxHelper personalizada , que pode ser usada em caixas de texto em todo o meu projeto. Porque achei que a inscrição nos eventos de todas as caixas de texto e de cada arquivo XAML individual para esse fim pode consumir muito tempo.

A classe TextBoxHelper que eu implementei possui os seguintes recursos:

  • Filtrando e aceitando apenas números em Duplo , Int , Uint e Natural formatos
  • Filtrando e aceitando apenas Mesmo ou Odd números
  • Manipulando manipulador de eventos de pasta para evitar colar texto inválido em nossas caixas de texto numéricas
  • Pode definir um valor padrão que será usado para evitar dados inválidos como a última captura, assinando o evento TextChanged das caixas de texto

Aqui está a implementação da classe 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;
            }
        }
    }
}

E aqui está um exemplo de seu uso fácil:

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

Ou

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

Observe que meu TextBoxHelper reside no alias viewHelpers xmlns.

Espero que esta implementação facilite o trabalho de outras pessoas :)

Amir Mahdi Nassiri
fonte
1
Isso é ótimo ao usar uma caixa de texto dentro de um DataTemplate, obrigado!
NucS
3
Ótima resposta, mas acho seus métodos difíceis de ler. Provavelmente você deve dividi-los em outros menores. Consulte Qual é o tamanho ideal de um método para você?
Anthony
Obrigado pelo feedback construtivo @Anthony
Amir Mahdi Nassiri
4
e.Handled = (int)e.Key >= 43 || (int)e.Key <= 34;

no evento de keydown de visualização da caixa de texto.

Novato
fonte
3
Não permite backspace embora.
sventevit 27/09/12
2
Backspace é 2, tab é 3
Daniel
6
-1, porque, na minha experiência, esse tipo de truque inteligente acaba mordendo sua bunda, como alguns outros comentadores observaram.
DonkeyMaster 18/02
A seta esquerda é 23, a seta direita é 25.
Aaron
4
PreviewTextInput += (s, e) =>
{
    e.Handled = !e.Text.All(char.IsDigit);
};
Julian Kowalczuk
fonte
2
isso também não aceita pontos ., pois e.Textretorna apenas o último caractere de entrada e um ponto falhará na IsDigitverificação.
Anthony
4

Para aqueles que procuram uma implementação rápida e muito simples para esse tipo de problema usando apenas números inteiros e decimais, no seu arquivo XAML, adicione uma PreviewTextInputpropriedade ao seu TextBoxe, em seguida, no seu arquivo xaml.cs, use:

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

É meio redundante continuar verificando toda a string toda vez que, como outros já mencionaram, você estiver fazendo alguma coisa com notação científica (embora, se você estiver adicionando certos caracteres como 'e', ​​uma regex simples que adicione símbolos / caracteres seja realmente simples e ilustrado em outras respostas). Mas, para valores simples de ponto flutuante, essa solução será suficiente.

Escrito como uma linha com uma expressão lambda:

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

Podemos fazer a validação no evento alterado da caixa de texto. A implementação a seguir impede a entrada de pressionamento de tecla diferente de numérico e um ponto decimal.

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;     
} 
kumar Gouraw
fonte
3

Que tal agora? Funciona bem para mim. Espero não ter perdido nenhum caso extremo ...

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();
    }
});
Shahin Dohan
fonte
2

No Windows Forms, era fácil; você pode adicionar um evento para o KeyPress e tudo funciona facilmente. No entanto, no WPF esse evento não está lá. Mas há uma maneira muito mais fácil para isso.

O WPF TextBox possui o evento TextChanged que é geral para tudo. Inclui colar, digitar e tudo o que puder vir à sua mente.

Então você pode fazer algo assim:

XAML:

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

CÓDIGO POR TRÁS:

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

Isso também aceita ., se você não quiser, basta removê-lo da regexdeclaração @[^\d].

Nota : Este evento pode ser usado em muitos TextBox'es, pois usa o senderTexto do objeto. Você só escreve o evento uma vez e pode usá-lo para vários TextBox'es.

Todos
fonte
2

Agora eu sei que esta pergunta tem uma resposta aceita , mas pessoalmente, acho um pouco confusa e acredito que deveria ser mais fácil do que isso. Então, tentarei demonstrar como consegui que funcionasse da melhor maneira possível:

No Windows Forms , há um evento chamado KeyPressque é perfeitamente bom para esse tipo de tarefa. Mas isso não existe no WPF ; portanto, usaremos o PreviewTextInputevento. Além disso, para a validação, acredito que se possa usar um foreachpara percorrer textbox.Texte verificar se ele corresponde ;) a condição, mas honestamente, é isso que expressões regulares servem as .

Mais uma coisa antes de mergulharmos no código sagrado . Para que o evento seja acionado, é possível fazer duas coisas:

  1. Use XAML para informar ao programa qual função chamar: <PreviewTextInput="textBox_PreviewTextInput/>
  2. Faça isso no Loadedevento do formulário (em que a caixa de texto está): textBox.PreviewTextInput += onlyNumeric;

Acho que o segundo método é melhor, porque em situações como essa, você precisará aplicar a mesma condição ( regex) a mais de um TextBoxe não deseja se repetir!.

Finalmente, veja como você faria isso:

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

Aqui está a minha versão. É baseado em uma ValidatingTextBoxclasse base que apenas desfaz o que foi feito se não for "válido". Ele suporta colar, cortar, excluir, backspace, +, - etc.

Para números inteiros de 32 bits, há uma classe Int32TextBox que apenas se compara a um int. Também adicionei classes de validação de ponto flutuante.

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

Nota 1: Ao usar a ligação WPF, certifique-se de usar a classe que se ajusta ao tipo de propriedade vinculada, caso contrário, poderá levar a resultados estranhos.

Nota 2: Ao usar classes de ponto flutuante com ligação WPF, verifique se a ligação usa a cultura atual para corresponder ao método TryParse que eu usei.

Simon Mourier
fonte
1

Usar:

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
Johnny
fonte
Uma explicação estaria em ordem.
Peter Mortensen
1

Eu estava trabalhando com uma caixa não acoplada para um projeto simples em que estava trabalhando, então não pude usar a abordagem de ligação padrão. Consequentemente, criei um hack simples que outras pessoas podem achar bastante útil, simplesmente estendendo o controle TextBox existente:

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

Obviamente, para um tipo flutuante, você deseja analisá-lo como um flutuador e assim por diante. Os mesmos princípios se aplicam.

Em seguida, no arquivo XAML, você precisa incluir o espaço para nome relevante:

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

Depois disso, você pode usá-lo como um controle regular:

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

Depois de usar algumas das soluções aqui por algum tempo, desenvolvi minha própria que funciona bem para minha configuração do MVVM. Observe que não é tão dinâmico quanto alguns dos outros, no sentido de ainda permitir que os usuários digitem caracteres errados, mas impede que eles pressionem o botão e façam qualquer coisa. Isso vai bem com o meu tema de esmaecer botões quando ações não podem ser executadas.

Eu tenho um TextBoxque um usuário deve digitar um número de páginas do documento a serem impressas:

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

... com esta propriedade de ligação:

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

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

Eu também tenho um botão:

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

... com esta ligação de comando:

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

        return _setNumberPagesCommand;
    }
}

E há o método de SetNumberOfPages(), mas não é importante para este tópico. Funciona bem no meu caso, porque não preciso adicionar nenhum código ao arquivo code-behind do View e me permite controlar o comportamento usando a Commandpropriedade

BK
fonte
1

No aplicativo WPF, você pode manipular isso manipulando o TextChangedevento:

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;
    }
}
Mehdi Khademloo
fonte
1

Para desenvolvedores que desejam que seus campos de texto aceitem números não assinados apenas como portas de soquete e assim por diante:

WPF

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

C #

private void Port_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    e.Handled = !int.TryParse(e.Text, out int x);
}
Beyondo
fonte
2
Observe que se você realmente deseja usar esse método com um campo de porta de soquete; Você precisaria verificar se o número inteiro é menor ou igual a 65535. Se for maior, não é uma porta válida. Além disso, a configuração de TextBox.MaxLengthpara 5ajudaria programaticamente ou em XAML .
Beyondo 26/07/19
0

Isto é o que eu usaria para obter uma caixa de texto WPF que aceita dígitos e o ponto decimal:

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

Coloque o código em um novo arquivo de classe, adicione

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

na parte superior do arquivo e construa a solução. O controle numericTextBox aparecerá na parte superior da caixa de ferramentas.

Matsolof
fonte
1
Veja a solução MUITO mais fácil anterior usando NumberValidationTextBox e expressões regulares. Isto é ridículo.
Scott Shaw-Smith
@ ScottShaw-Smith Talvez a solução aceita seja menos código, mas não é mais rápida que isso. Sempre existem alguns projetos que exigem muito poder de processamento, em vez de usar regex.
Beyondo 26/07/19