Vra

Hoe is jy die hantering van die inskrywing van die numeriese waardes in die WPF aansoeke?

Sonder'n NumericUpDown beheer, ek het al met behulp van'n Teksboks en die hantering van sy PreviewKeyDown geval met die kode hieronder, maar dit is redelik lelik.

Het iemand gevind'n meer grasieuse manier om te kry numeriese data van die gebruiker sonder om te vertrou op'n derde-party beheer?

private void NumericEditPreviewKeyDown(object sender, KeyEventArgs e)
{
    bool isNumPadNumeric = (e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || e.Key == Key.Decimal;
    bool isNumeric = (e.Key >= Key.D0 && e.Key <= Key.D9) || e.Key == Key.OemPeriod;

    if ((isNumeric || isNumPadNumeric) && Keyboard.Modifiers != ModifierKeys.None)
    {
        e.Handled = true;
        return;
    }

    bool isControl = ((Keyboard.Modifiers != ModifierKeys.None && Keyboard.Modifiers != ModifierKeys.Shift)
        || e.Key == Key.Back || e.Key == Key.Delete || e.Key == Key.Insert
        || e.Key == Key.Down || e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up
        || e.Key == Key.Tab
        || e.Key == Key.PageDown || e.Key == Key.PageUp
        || e.Key == Key.Enter || e.Key == Key.Return || e.Key == Key.Escape
        || e.Key == Key.Home || e.Key == Key.End);

    e.Handled = !isControl && !isNumeric && !isNumPadNumeric;
}
Was dit nuttig?

Oplossing

Hoe gaan dit:

protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
{
    e.Handled = !AreAllValidNumericChars(e.Text);
    base.OnPreviewTextInput(e);
}

private bool AreAllValidNumericChars(string str)
{
    foreach(char c in str)
    {
        if(!Char.IsNumber(c)) return false;
    }

    return true;
}

Ander wenke

Dit is hoe ek dit doen. Dit maak gebruik van 'n gewone uitdrukking om te kyk of die teks wat sal wees in die boks is numeriese of nie.

Regex NumEx = new Regex(@"^-?\d*\.?\d*$");

private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    if (sender is TextBox)
    {
        string text = (sender as TextBox).Text + e.Text;
        e.Handled = !NumEx.IsMatch(text);
    }
    else
        throw new NotImplementedException("TextBox_PreviewTextInput Can only Handle TextBoxes");
}

Daar is nou 'n baie beter manier om dit te doen in WPF en Silver. As jou beheer is gebind om 'n eiendom, al wat jy hoef te doen is verander jou bindende verklaring 'n bietjie. Gebruik die volgende vir jou bind:

<TextBox Text="{Binding Number, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/>

Let daarop dat jy dit ook kan gebruik op persoonlike eienskappe, al wat jy hoef te doen is gooi 'n uitsondering as die waarde in die boks is ongeldig en die beheer sal kry uitgelig met 'n rooi grens. As jy kliek op die boonste regterkant van die rooi grens dan die uitsondering boodskap sal verskyn.

Ek het al met behulp van'n aangehegte eiendom aan die gebruiker toelaat om te gebruik die op en af sleutels om te verander die waardes in die teks boks.Om dit te gebruik, jy moet net gebruik

<TextBox local:TextBoxNumbers.SingleDelta="1">100</TextBox>

Dit maak nie eintlik spreek die validering kwessies wat na verwys word in hierdie vraag, maar dit spreek van wat ek doen oor nie met'n numeriese op/af beheer.Die gebruik van dit vir'n bietjie, ek dink ek kan eintlik soos dit beter as die ou numeriese op/af beheer.

Die kode is nie volmaak nie, maar dit hanteer die gevalle wat ek nodig het om dit te hanteer:

  • Up pyl, Down pyltjie
  • Shift + Up pyl, Shift + Down pyltjie
  • Page Up, Page Down
  • Bindend Converter op die teks eiendom

Code behind

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;

namespace Helpers
{
    public class TextBoxNumbers
    {    
        public static Decimal GetSingleDelta(DependencyObject obj)
        {
            return (Decimal)obj.GetValue(SingleDeltaProperty);
        }

        public static void SetSingleDelta(DependencyObject obj, Decimal value)
        {
            obj.SetValue(SingleDeltaProperty, value);
        }

        // Using a DependencyProperty as the backing store for SingleValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SingleDeltaProperty =
            DependencyProperty.RegisterAttached("SingleDelta", typeof(Decimal), typeof(TextBoxNumbers), new UIPropertyMetadata(0.0m, new PropertyChangedCallback(f)));

        public static void f(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            TextBox t = o as TextBox;

            if (t == null)
                return;

            t.PreviewKeyDown += new System.Windows.Input.KeyEventHandler(t_PreviewKeyDown);
        }

        private static Decimal GetSingleValue(DependencyObject obj)
        {
            return GetSingleDelta(obj);
        }

        private static Decimal GetDoubleValue(DependencyObject obj)
        {
            return GetSingleValue(obj) * 10;
        }

        private static Decimal GetTripleValue(DependencyObject obj)
        {
            return GetSingleValue(obj) * 100;
        }

        static void t_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            TextBox t = sender as TextBox;
            Decimal i;

            if (t == null)
                return;

            if (!Decimal.TryParse(t.Text, out i))
                return;

            switch (e.Key)
            {
                case System.Windows.Input.Key.Up:
                    if (Keyboard.Modifiers == ModifierKeys.Shift)
                        i += GetDoubleValue(t);
                    else
                        i += GetSingleValue(t);
                    break;

                case System.Windows.Input.Key.Down:
                    if (Keyboard.Modifiers == ModifierKeys.Shift)
                        i -= GetDoubleValue(t);
                    else
                        i -= GetSingleValue(t);
                    break;

                case System.Windows.Input.Key.PageUp:
                    i += GetTripleValue(t);
                    break;

                case System.Windows.Input.Key.PageDown:
                    i -= GetTripleValue(t);
                    break;

                default:
                    return;
            }

            if (BindingOperations.IsDataBound(t, TextBox.TextProperty))
            {
                try
                {
                    Binding binding = BindingOperations.GetBinding(t, TextBox.TextProperty);
                    t.Text = (string)binding.Converter.Convert(i, null, binding.ConverterParameter, binding.ConverterCulture);
                }
                catch
                {
                    t.Text = i.ToString();
                }
            }
            else
                t.Text = i.ToString();
        }
    }
}

Ek het besluit om die antwoord gemerk as die antwoord op hier te vereenvoudig om basies 2 lyne met behulp van 'n LINQ uitdrukking.

e.Handled = !e.Text.All(Char.IsNumber);
base.OnPreviewTextInput(e);

Ek gebruik 'n persoonlike ValidationRule om te kyk of teks is numeriese.

public class DoubleValidation : ValidationRule
{
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        if (value is string)
        {
            double number;
            if (!Double.TryParse((value as string), out number))
                return new ValidationResult(false, "Please enter a valid number");
        }

        return ValidationResult.ValidResult;
    }

Toe ek 'n TextBox om 'n numeriese eiendom bind, ek voeg die nuwe persoonlike klas aan die Binding.ValidationRules versameling. In die onderstaande valideringsreël voorbeeld is elke keer nagegaan die TextBox.Text veranderinge.

<TextBox>
    <TextBox.Text>
        <Binding Path="MyNumericProperty" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:DoubleValidation/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

Hoekom het jy nie probeer net die gebruik van die KeyDown geleentheid eerder as die PreviewKeyDown Event. Jy kan die ongeldige karakters daar stop nie, maar al beheer karakters die aanvaar. Dit lyk vir my werk:

private void NumericKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
    bool isNumPadNumeric = (e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9);
    bool isNumeric =((e.Key >= Key.D0 && e.Key <= Key.D9) && (e.KeyboardDevice.Modifiers == ModifierKeys.None));
    bool isDecimal = ((e.Key == Key.OemPeriod || e.Key == Key.Decimal) && (((TextBox)sender).Text.IndexOf('.') < 0));
    e.Handled = !(isNumPadNumeric || isNumeric || isDecimal);
}
public class NumericTextBox : TextBox
{
    public NumericTextBox()
        : base()
    {
        DataObject.AddPastingHandler(this, new DataObjectPastingEventHandler(CheckPasteFormat));
    }

    private Boolean CheckFormat(string text)
    {
        short val;
        return Int16.TryParse(text, out val);
    }

    private void CheckPasteFormat(object sender, DataObjectPastingEventArgs e)
    {
        var isText = e.SourceDataObject.GetDataPresent(System.Windows.DataFormats.Text, true);

        if (isText)
        {
            var text = e.SourceDataObject.GetData(DataFormats.Text) as string;
            if (CheckFormat(text))
            {
                return;
            }
        }

        e.CancelCommand();
    }

    protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
    {
        if (!CheckFormat(e.Text))
        {
            e.Handled = true;
        }
        else
        {
            base.OnPreviewTextInput(e);
        }
    }
}

Verder kan jy die ontleding gedrag aan te pas deur die verskaffing van gepaste afhanklikheid eienskappe.

Die kombinasie van die idees van 'n paar van hierdie antwoorde, het ek 'n NumericTextBox geskep dat

  • Hanteer desimale
  • Is 'n paar basiese validering te verseker enige ingevoer '-' '. "Of geldig
  • handvatsels geplak waardes

Neem asseblief die vrymoedigheid om te werk as jy kan dink aan enige ander logika wat ingesluit moet word.

public class NumericTextBox : TextBox
{
    public NumericTextBox()
    {
        DataObject.AddPastingHandler(this, OnPaste);
    }

    private void OnPaste(object sender, DataObjectPastingEventArgs dataObjectPastingEventArgs)
    {
        var isText = dataObjectPastingEventArgs.SourceDataObject.GetDataPresent(System.Windows.DataFormats.Text, true);

        if (isText)
        {
            var text = dataObjectPastingEventArgs.SourceDataObject.GetData(DataFormats.Text) as string;
            if (IsTextValid(text))
            {
                return;
            }
        }

        dataObjectPastingEventArgs.CancelCommand();
    }

    private bool IsTextValid(string enteredText)
    {
        if (!enteredText.All(c => Char.IsNumber(c) || c == '.' || c == '-'))
        {
            return false;
        }

        //We only validation against unselected text since the selected text will be replaced by the entered text
        var unselectedText = this.Text.Remove(SelectionStart, SelectionLength);

        if (enteredText == "." && unselectedText.Contains("."))
        {
            return false;
        }

        if (enteredText == "-" && unselectedText.Length > 0)
        {
            return false;
        }

        return true;
    }

    protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
    {
        e.Handled = !IsTextValid(e.Text);
        base.OnPreviewTextInput(e);
    }
}

Jy kan ook probeer om met behulp van data validering as gebruikers data te pleeg voor jy dit gebruik. Doen wat ek gevind het was redelik eenvoudig en skoner as fiddling oor met sleutels.

Andersins, jy kan altyd plak te skakel!

My weergawe van Arcturus beantwoord, kan die skakel metode te verander gebruik om te werk met int / uint / desimale / byte (vir kleure) of enige ander numeriese formaat jy omgee om te gebruik, werk ook met kopie / plak

protected override void OnPreviewTextInput( System.Windows.Input.TextCompositionEventArgs e )
{
    try
    {
        if ( String.IsNullOrEmpty( SelectedText ) )
        {
            Convert.ToDecimal( this.Text.Insert( this.CaretIndex, e.Text ) );
        }
        else
        {
            Convert.ToDecimal( this.Text.Remove( this.SelectionStart, this.SelectionLength ).Insert( this.SelectionStart, e.Text ) );
        }
    }
    catch
    {
        // mark as handled if cannot convert string to decimal
        e.Handled = true;
    }

    base.OnPreviewTextInput( e );
}

N.B. Ongetoets kode.

Voeg dit by die belangrikste oplossing om seker te maak die die bindende opgedateer na nul toe die teksboks is skoongemaak.

protected override void OnPreviewKeyUp(System.Windows.Input.KeyEventArgs e)
{
    base.OnPreviewKeyUp(e);

    if (BindingOperations.IsDataBound(this, TextBox.TextProperty))
    {
        if (this.Text.Length == 0)
        {
            this.SetValue(TextBox.TextProperty, "0");
            this.SelectAll();
        }
    }
}

Call me crazy, maar waarom nie sit plus en minus knoppies aan weerskante van die teksboks beheer en eenvoudig te verhoed dat die teksboks vanaf die ontvangs wyser fokus en sodoende jou eie goedkoop NumericUpDown beheer skep?

private void txtNumericValue_PreviewKeyDown(object sender, KeyEventArgs e)
{
    KeyConverter converter = new KeyConverter();

    string key = converter.ConvertToString(e.Key);

    if (key != null && key.Length == 1)
    {
        e.Handled = Char.IsDigit(key[0]) == false;
    }
}

Dit is die maklikste tegniek Ek het gevind om dit te bewerkstellig. Die negatiewe kant is dat die konteks kieslys van die teksboks kan nog nie-numeriese vereistes via plak. Context = "{x:: Null}" om hierdie vinnig op te los ek net die kenmerk / eienskap by die teksboks dit daardeur uit te skakel. Nie ideaal, maar vir my scenario dit sal voldoende wees.

Dit is duidelik dat jy kan 'n paar meer sleutels / karakters by te voeg in die toets om bykomende aanvaarbare waardes insluit (bv. ',' $ 'Ens ...)

Private Sub Value1TextBox_PreviewTextInput(ByVal sender As Object, ByVal e As TextCompositionEventArgs) Handles Value1TextBox.PreviewTextInput
    Try
        If Not IsNumeric(e.Text) Then
            e.Handled = True
        End If
    Catch ex As Exception
    End Try
End Sub

vir my gewerk het.

Kan jy nie net gebruik iets soos die volgende?

int numericValue = 0;

if (false == int.TryParse(yourInput, out numericValue))
{
    // handle non-numeric input
}
void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
{
    string sVal = e.Text;
    int val = 0;

    if (sVal != null && sVal.Length > 0)
    {
        if (int.TryParse(sVal, out val))
        {
            e.Handled = false;
        }
        else
        {
            e.Handled = true;
        }
    }
}

Kan ook 'n converter soos gebruik:

public class IntegerFormatConverter : IValueConverter
{
    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        int result;
        int.TryParse(value.ToString(), out result);
        return result;
    }

    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        int result;
        int.TryParse(value.ToString(), out result);
        return result;
    }
}
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top