Bir TextBox'ı yalnızca WPF'deki sayısal girdiyi kabul edecek şekilde nasıl edinebilirim?


335

Rakamları ve ondalık noktayı kabul ediyorum, ancak işaret yok.

Windows Forms için NumericUpDown denetimi ve Microsoft'tan bir NumericUpDown özel denetim örneği bu örneklere baktım . Ama şimdiye kadar NumericUpDown (WPF tarafından destekleniyor veya desteklenmiyor) istediğim işlevselliği sağlamayacak gibi görünüyor. Uygulamamın tasarlanma şekli, sağ aklında kimse oklarla uğraşmak istemeyecek. Uygulamam bağlamında pratik bir anlam ifade etmiyorlar.

Bu yüzden standart bir WPF TextBox sadece istediğim karakterleri kabul etmek için basit bir yol arıyorum. Mümkün mü? Pratik mi?

Yanıtlar:


418

Bir önizleme metni giriş etkinliği ekleyin. Gibi o kadar: <TextBox PreviewTextInput="PreviewTextInput" />.

Daha sonra e.Handledbu metin içinde izin verilmiyorsa ayarlayın.e.Handled = !IsTextAllowed(e.Text);

Yazdıklarına IsTextAllowedizin verilip verilmeyeceğini görmek için yöntemde basit bir normal ifade kullanıyorum . Benim durumumda sadece sayılara, noktalara ve tirelere izin vermek istiyorum.

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

Yanlış verilerin yapıştırılmasını önlemek istiyorsanız, DataObject.Pastingetkinliği buradaDataObject.Pasting="TextBoxPasting" gösterildiği gibi bağlayın (kod alıntılanmıştır):

// 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
Normal ifadeniz önemliyse bilimsel gösterime (1e5) izin vermez.
Ron Warholic

14
Bu cevabın sadece yazdıklarınızı kontrol ettiğine dikkat edin, böylece 3 -3 girebilirsiniz
David Sykes

153
Cevabın amacı mükemmel Regex'i belirtmek değildi, birisinin ne yazdığını filtrelemek için WPF'nin nasıl kullanılacağını göstermekti.
Ray

27
[Space] PreviewTextInput olayını tetiklemiyor.
peterG

5
Böyle bir şey double.TryParse()muhtemelen aynı sayıda çizgi ile uygulanacak ve daha esnek olacaktır.
Thomas Weller

190

Olay işleyici metin girişini önizliyor. Burada, normal bir ifade yalnızca bir sayı değilse metin girişiyle eşleşir ve daha sonra giriş metin kutusuna yapılmaz.

Yalnızca harf istiyorsanız, normal ifadeyi olarak değiştirin [^a-zA-Z].

XAML

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

XAML.CS DOSYASI

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

1
Olay işleyicisi önizleme metin girişidir. Burada normal ifade, yalnızca bir sayı değilse, metin girişiyle eşleşirse, metin kutusuna giriş yapılmaz. Yalnızca alfabe istiyorsanız, normal ifadeyi [^ a-zA-Z] olarak değiştirin.
Kishor

Sayılar, ondalıklar ve operatörler ne olacak?
Jason Ebersey

Başka bir STATIC sınıfında bildirildiğinde ve metin kutusuna uygulandığında lütfen bunu nasıl kullanacağımı bana bildirin.
SHEKHAR SHETE

3
Bunu gerçek cevaptan daha çok seviyorum, kısa ve basit. Gerçek cevap aynı sonucu elde etmek için iki yönteme ihtiyaç duyar.
Şerit

1
@Jagd Önerilen cevap endişelerin daha iyi ayrılmasıdır. Ancak, bu doğrulamada da çok sayıda metin kutusu ayarlayabilirsiniz. PreviewTextInput = "NumberValidationTextBox" öğesini eklemeniz yeterlidir. (tıpkı diğer cevap gibi!)
Sliver

84

Zaten burada olanlardan bazılarını kullandım ve bir davranış kullanarak kendi bükümümü koydum, bu yüzden bu kodu bir ton Görünüm boyunca yaymak zorunda değilim ...

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

Alakalı görünüm kodu:

<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
Bu harika çözümden esinlenerek bazı iyileştirmeler yaptım. Lütfen aşağıdaki konuya bakınız.
Alex Klaus

2
Selam. Bunun biraz geç olduğunu biliyorum ama bunu uygulamaya çalışıyorum ama hata almaya devam ediyorum. Bazı referansları kaçırdığımı tahmin ediyorum. Bir sınıf oluşturduktan sonra varsayılanlar dışında yazılması gereken herhangi bir var mı?
Teklif

1
@ Teklif Evet, xaml pencerenizin en üstüne xmlns: interactivity = " schemas.microsoft.com/expression/2010/interactivity " ifadesini eklediğinizden emin olun .
WiteCastle

İfade artık kullanılmıyor. Bu yaklaşım temiz olsa da, artık sürdürülmeyen bir kod kullanıyor.
Robert Baker

1
Bu nedenle, döndürmek için IsValid işlevini düzenlerseniz! ExceedMaxLength (newText, paste) && Regex.IsMatch (String.Concat (this.AssociatedObject.Text, newText), RegularExpression); bu tüm dizeyi değerlendirir. Btw - davranışları ile bu seçeneği seviyorum !!
Rogala

59

Bu, WilP'nin cevabının geliştirilmiş bir çözümüdür . Gelişmelerim:

  • Del ve Backspace düğmelerinde geliştirilmiş davranış
  • EmptyValueBoş dize uygun değilse özellik eklendi
  • Bazı küçük yazım hataları düzeltildi
/// <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] --------------------------------
}

Kullanımı oldukça basittir:

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

1
Bu çözüm çok daha iyi. Ancak küçük bir hata yaptınız: Yeni metni test ederken MaxLengthdurumunuzu ayarlamadığınız (this.MaxLength == 0 || text.Length <= this.MaxLength)zaman her falsezaman geri döner . Bunun için varsayılan değer olarak (this.MaxLength == int.MinValue || text.Length <= this.MaxLength)ayarladığınızdan daha iyi olmalıdır . int.MinValueMaxLength
Christoph Meißner

1
Teşekkür ederim @Christoph, evet, haklısın. Cevabımı değiştirdim.
Alex Klaus

@AlexKlaus bu UpdateSourceTrigger=PropertyChangedbağlama eklemek kadar harika çalışıyor . Herhangi bir fikir değiştirilirken bu kodun çalışması için UpdateSourceTriggernasıl ayarlanır PropertyChanged? Bu kodu paylaştığınız için teşekkür ederiz.
Junior

32

MVVM kullanarak bunu yapmanın çok basit ve kolay bir yolu.

Görünüm modelinde bir tamsayı özelliği ile textBox'ınızı bağlayın ve bu bir mücevher gibi çalışacaktır ... metin kutusuna bir tamsayı girilmediğinde bile doğrulama gösterecektir.

XAML kodu:

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

Model kodunu görüntüle:

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

Ama soru "Rakamları ve ondalık noktayı kabul etmek istiyorum" içeriyordu . Bu cevap için ondalık sayı kabul edildi mi?
Peter Mortensen

Geçiş longyapmayı denedim float, ancak anında doğrulama ile pek doğru çalışmadı. Bağlamaya ekledim UpdateSourceTrigger="PropertyChanged", bu yüzden her karakter yazılırken doğrulama gerçekleştirecekti ve artık bir '.' geçersiz bir karakter ("1x.234" yazıp "x" i silmek zorunda kalmadıkça). Ayrıca bu modda biraz halsiz hissediyor. Bu System.Number.ParseSingle()işi yapmak için kullanılıyor gibi görünüyor , bu yüzden çeşitli gösterimleri kabul ediyor.
Faden

@wolle, onaylamanın nasıl çalıştığını açıklayamadığı için muhtemelen oy kullanmıyor.
Paul McCarthy

26

Metin değiştiğinde, verilerin sayısal olup olmadığını kontrol edip etmediğini ve işlenmeye devam etmesine izin verip vermediğini kontrol edip onaylamıyorsa, kullanıcıya bu alanda yalnızca sayısal verilerin kabul edildiğini soracak şekilde bir VALİDASYON KURALI ekleyin.

Windows Presentation Foundation'da Doğrulama hakkında daha fazla bilgi edinin


6
Bu gerçekten SO standartları için bir cevap değildir.
Robert Baker

Bunu yapmanın .net yolu gibi görünüyor.
Telemat

1
Olduğu doğru cevap: doğrulama viene modeli veya model seviyesinde olmalıdır. Dahası, benzer bir sayısal türe bağlanabilir doubleve bu size zaten standart bir doğrulama sağlar.


20

Ayrıca bir doğrulama kuralı uygulayabilir ve bunu TextBox'a uygulayabilir:

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

Kuralın aşağıdaki şekilde uygulanmasıyla (diğer cevaplarda önerilenlerle aynı Regex'i kullanarak):

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

Ondalık basamaklar girmek istiyorsanız, Metin "ile" sona erdiğinde "geçerli" değerini döndürmeyin. Lütfen stackoverflow.com/a/27838893/417939
YantingChen

14

Burada Ray'ın cevabından ilham alan basit bir çözümüm var . Bu, herhangi bir sayı biçimini tanımlamak için yeterli olmalıdır.

Bu çözüm, yalnızca pozitif sayılar, tam sayı değerleri veya maksimum ondalık basamağa kadar doğru değerler vb. İstiyorsanız kolayca değiştirilebilir.


Ray'ın cevabında önerildiği gibi , önce bir PreviewTextInputetkinlik eklemeniz gerekir :

<TextBox PreviewTextInput="TextBox_OnPreviewTextInput"/>

Ardından, arkasındaki koda aşağıdakileri koyun:

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
Bu cevabı çok seviyorum, basit ve etkili +
Pulle

tanrı ve basit ama onun çirkin boşluk sağlar
Momo

2
Bu hala birisinin metin kutusuna bir dize yapıştırmasına izin verir
FCin

8

Sayısal tuş takımı numaralarına ve geri tuşuna izin verdim:

    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 yerine enum değerlerini kullanmanızı 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);
öneririm

7

Bunu varsayacağım:

  1. Sayısal girdiye izin vermek istediğiniz TextBox'ınızda yalnızca Text özelliği başlangıçta geçerli bir sayı değerine ayarlanır (örneğin, 2.7172).

  2. Metin Kutunuz ana pencerenizin alt öğesidir

  3. Ana pencereniz Window1 sınıfında

  4. TextBox adınız numericTB

Temel fikir:

  1. Ekle: private string previousText;ana pencere sınıfınıza (Window1)

  2. Ekle: previousText = numericTB.Text;ana pencere oluşturucunuza

  3. NumericTB.TextChanged olayının aşağıdaki gibi olması için bir işleyici oluşturun:

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

Bu, geçerli olduğu sürece previousText öğesini numericTB.Text değerine ayarlamaya devam eder ve kullanıcı hoşunuza gitmeyen bir şey yazarsa numericTB.Text öğesini son geçerli değerine ayarlar. Tabii ki, bu sadece temel bir fikirdir ve "salak kanıtı" değil, sadece "salak dayanıklılığı" dır. Örneğin, kullanıcının boşluklarla uğraştığı durumu ele almaz. İşte size "aptal kanıtı" olduğunu düşündüğüm tam bir çözüm ve eğer yanlışsam lütfen bana söyleyin:

  1. Window1.xaml dosyanızın içeriği:

    <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 dosyanızın içeriği:

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

Ve bu kadar. Çok sayıda TextBox'ınız varsa, TextBox'tan miras alan bir CustomControl oluşturmanızı öneririm, böylece previousText ve numericTB_TextChanged'i ayrı bir dosyada sarabilirsiniz.


Vay be bu harika! Önde olumsuz bir simgeye nasıl izin verebilirim?
theNoobGuy

6

Gereken tek kod budur:

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

Bu yalnızca sayıların metin kutusuna girilmesine izin verir.

Ondalık basamak veya eksi işaretine izin vermek için, normal ifadeyi olarak değiştirebilirsiniz [^0-9.-]+.


1
Bir küçük nitpick dışında çok iyi bir çözüm: Önizleme alanlarına girmenizi engellemez, çünkü bunlar PreviewTextInput olayını tetiklemez.
Tim Pohlmann

Backspace de ateşlemez.
Winger Sendon

6

Temel bir işlev (insanların neden uzun yöntemler yaptığını bilmiyorum) yapmak için çok fazla kod yazmak istemiyorsanız, sadece bunu yapabilirsiniz:

  1. Ad alanı ekle:

    using System.Text.RegularExpressions;
  2. XAML'de bir TextChanged özelliği ayarlayın:

    <TextBox x:Name="txt1" TextChanged="txt1_TextChanged"/>
  3. WPF'de txt1_TextChanged yöntemi altında şunu ekleyin Regex.Replace:

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

2
Davranış veya AttachedProperty kullanmak çok daha temizdir. Her görünümde / her metin kutusu için arka planda kodlama yok
Sir Rufo

Çalışabilir ama havuç metin
Momo

6

Başka bir yaklaşım, ekli bir davranış kullanarak olacak, benim proje tüm metin kutuları üzerinde kullanılabilen benim özel TextBoxHelper sınıf uyguladım . Çünkü her metin kutusu ve her XAML dosyasındaki olaylara abone olmanın bu amaçla zaman alabileceğini düşündüm.

Uyguladığım TextBoxHelper sınıfı şu özelliklere sahiptir:

  • Yalnızca Double , Int , Uint ve Natural biçimindeki sayıları filtreleme ve kabul etme
  • Yalnızca Çift veya Tek sayıları filtreleme ve kabul etme
  • Sayısal metin kutularımıza geçersiz metin yapışmasını önlemek için yapıştır olay işleyicisini işleme
  • TextChanged olayına abone olarak geçersiz verileri son çekim olarak önlemek için kullanılacak bir Varsayılan Değer ayarlayabilir

İşte TextBoxHelper sınıfının uygulanması:

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

Ve kolay kullanımının bir örneği:

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

Veya

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

Not olduğunu viewHelpers xmlns takma benim TextBoxHelper bulunduğu.

Umarım bu uygulama başkalarının çalışmalarını kolaylaştırır :)


1
Bu DataTemplate içinde bir metin kutusu kullanırken harika, teşekkürler!
NucS

3
Harika bir cevap ama yöntemlerinizin okunmasını zor buluyorum. Muhtemelen onları küçük parçalara ayırmalısınız. Bkz . Bir yöntemin sizin için ideal uzunluğu nedir?
Anthony

@Anthony
Amir Mahdi

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

metin kutusunun önizleme tuş etkinliği.


3
Gerçi geri almasına izin vermez.
sventevit

2
Backspace 2, sekme 3
Daniel

6
-1 Çünkü tecrübelerime göre, bu tür akıllı numaralar sonunda diğer kıdemsizlerin de belirttiği gibi seni kıçından ısırıyor.
DonkeyMaster

Sol ok 23, Sağ ok 25.
Aaron

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

2
bu yalnızca nokta kabul etmez ., çünkü e.Textyalnızca son giriş karakterini döndürür ve bir nokta denetimde başarısız olur IsDigit.
Anthony

4

Yalnızca tamsayı ve ondalık kullanarak bu tür bir sorun için hızlı ve çok basit bir uygulama arayanlar için, XAML dosyanıza bir PreviewTextInputözellik ekleyin TextBoxve ardından xaml.cs dosya kullanımınıza bir özellik ekleyin :

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

Diğerlerinin de belirttiği gibi, bilimsel gösterimle bir şey yapmıyorsanız ('e' gibi belirli karakterler ekleseniz de, semboller / karakterler ekleyen basit bir regex gerçekten basit ve diğer cevaplarda resimli). Ancak basit kayan nokta değerleri için bu çözüm yeterli olacaktır.

Lambda ifadesi ile tek astar olarak yazılmıştır:

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

3

Metin kutusu değişti olayında doğrulama yapabiliriz. Aşağıdaki uygulama, sayısal ve bir ondalık nokta dışındaki tuş basma girişlerini engeller.

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

Buna ne dersin? Benim için iyi çalışıyor. Umarım herhangi bir uç vakayı kaçırmadım ...

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'da bu kolaydı; KeyPress için bir etkinlik ekleyebilirsiniz ve her şey kolayca çalışır. Ancak, WPF'de bu olay yoktur. Ama bunun için çok daha kolay bir yol var.

WPF TextBox, her şey için genel olan TextChanged olayına sahiptir. Yapıştırma, yazma ve aklınıza gelebilecek her şeyi içerir.

Böylece böyle bir şey yapabilirsiniz:

XAML:

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

ARKA KOD:

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

Bu da kabul .etmez, eğer istemiyorsanız, sadece regexifadeden çıkarın @[^\d].

Not : Bu olay, sendernesnenin Metnini kullandığı için birçok TextBox'da kullanılabilir . Etkinliği yalnızca bir kez yazarsınız ve birden çok TextBox için kullanabilirsiniz.


2

Şimdi bu sorunun kabul edilmiş bir cevabı olduğunu biliyorum , ama şahsen biraz kafa karıştırıcı buluyorum ve bundan daha kolay olması gerektiğine inanıyorum. Bu yüzden elimden geldiğince en iyi şekilde nasıl çalıştığımı göstermeye çalışacağım:

In Windows Forms denilen bir olay var KeyPressgörevin bu tür mükemmel iyidir. Ama bu var olmayan WPF bunun yerine, kullanacağınız, PreviewTextInputolayı. Ayrıca, doğrulama için, bir tane bir kullanabilirsiniz inanıyoruz foreachdöngü textbox.Textve kontrol maçları ;) koşulu, ama dürüst, nedir bu normal ifadeler içindir.

Kutsal koda girmeden önce bir şey daha var . Etkinliğin başlatılması için iki şey yapılabilir:

  1. Programa hangi işlevi çağıracağını söylemek için XAML kullanın: <PreviewTextInput="textBox_PreviewTextInput/>
  2. Do it Loaded(metin kutusu olan) formun olay: textBox.PreviewTextInput += onlyNumeric;

İkinci yöntemin daha iyi olduğunu düşünüyorum çünkü böyle durumlarda, çoğunlukla aynı koşulu ( regex) birden fazla uygulamaya uygulamanız istenir TextBoxve kendinizi tekrarlamak istemezsiniz! .

Son olarak, bunu nasıl yapacaksınız:

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

İşte benim versiyonum. Bir tabana dayanıyorValidatingTextBox"Geçerli" değilse yapılanları geri sınıfa . Yapıştır, kes, sil, geri al, +, - vb.

32 bit tam sayı için, yalnızca int ile karşılaştırılan bir Int32TextBox sınıfı vardır. Ayrıca kayan nokta doğrulama sınıfları ekledim.

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

Not 1: WPF bağlayıcısını kullanırken, bound özelliği türüne uyan sınıfı kullandığınızdan emin olmanız gerekir, aksi takdirde garip sonuçlara yol açabilir.

Not 2: Kayan nokta sınıflarını WPF bağlama ile kullanırken, bağlamanın kullandığım TryParse yöntemiyle eşleşmesi için geçerli kültürü kullandığından emin olun.



1

kullanın:

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

Bir açıklama yapılabilir.
Peter Mortensen

1

Üzerinde çalıştığım basit bir proje için bağlı olmayan bir kutu ile çalışıyordum, bu yüzden standart bağlama yaklaşımını kullanamadım. Sonuç olarak, sadece mevcut TextBox kontrolünü genişleterek diğerlerinin oldukça kullanışlı bulabileceği basit bir kesmek yarattım:

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

Açıkçası, kayan bir tip için, bunu bir şamandıra olarak ayrıştırmak istersiniz vb. Aynı ilkeler geçerlidir.

Daha sonra XAML dosyasına ilgili ad alanını eklemeniz gerekir:

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

Bundan sonra düzenli kontrol olarak kullanabilirsiniz:

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

1

Bir süre burada bazı çözümleri kullandıktan sonra, MVVM kurulumum için iyi çalışan kendi çözümlerimi geliştirdim. Kullanıcıların hala hatalı karakterler girmesine izin verme anlamında diğerlerinden biri kadar dinamik olmadığını, ancak düğmeye basmasını ve böylece herhangi bir şey yapmasını engellediğini unutmayın. Bu, eylemler gerçekleştirilemediğinde düğmelerin grileşmesi temamla iyi gider.

TextBoxBir kullanıcının yazdırılacak birkaç belge sayfası girmesi gereken bir şey var :

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

... bu ciltleme özelliğiyle:

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

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

Ayrıca bir düğme var:

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

... bu komut bağlama ile:

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

        return _setNumberPagesCommand;
    }
}

Ve sonra yöntemi var SetNumberOfPages(), ama bu konu için önemsiz. Benim durumumda iyi çalışır çünkü ben View's code-behind dosyasına herhangi bir kod eklemek zorunda değilim ve Commandözelliği kullanarak davranışı kontrol etmek için izin verir .



1

WPF uygulamasında, TextChangedolayı işleyerek bunu gerçekleştirebilirsiniz:

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

Metin alanlarının yalnızca soket bağlantı noktaları gibi imzalanmamış sayıları kabul etmesini isteyen geliştiriciler için:

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

2
Bu yöntemi gerçekten bir soket bağlantı noktası alanıyla kullanmak istiyorsanız; Tamsayıdan küçük veya ona eşit olup olmadığını kontrol etmeniz gerekir 65535. Daha büyükse geçerli bir bağlantı noktası değildir. Ayrıca, TextBox.MaxLengthdeğerini ayarlamak programlı olarak veya XAML'de5 yardımcı olacaktır .
Beyondo

0

Bu basamakları ve ondalık noktasını kabul eden bir WPF metin kutusu almak için kullanacağım şey:

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

Kodu yeni bir sınıf dosyasına koyun, ekleyin

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

tıklayın ve çözümü oluşturun. NumericTextBox denetimi araç kutusunun üstünde görünecektir.


1
NumberValidationTextBox ve normal ifadeleri kullanarak önceki ÇOK daha kolay çözüme bakın. Bu gülünç.
Scott Shaw-Smith

@ ScottShaw-Smith Belki kabul edilen çözüm daha az koddur, ancak bundan daha hızlı değildir. Normal ifade kullanmak yerine çok fazla işlem gücü gerektiren bazı projeler her zaman vardır.
Beyondo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.