WPF – TextBox Input Behavior


Hier mal ein nettes Behavior was ich recht häufig benutze, um Eingaben in einer TextBox zu beschränken. Die Anwendung ist ganz einfach:

<TextBox>
    <i:Interaction.Behaviors>
       <behaviors:TextBoxInputBehavior InputMode="DigitInput"/>
    </i:Interaction.Behaviors>
</TextBox>

Und hier der Code dazu:

    public class TextBoxInputBehavior : Behavior<TextBox>
    {
        const NumberStyles validNumberStyles = NumberStyles.AllowDecimalPoint |
                                                   NumberStyles.AllowThousands |
                                                   NumberStyles.AllowLeadingSign;
        public TextBoxInputBehavior()
        {
            this.InputMode = TextBoxInputMode.None;
            this.JustPositivDecimalInput = false;
            this.MaxVorkommastellen = null;
        }

        public TextBoxInputMode InputMode { get; set; }

        public ushort? MaxVorkommastellen { get; set; }
        
        public static readonly DependencyProperty JustPositivDecimalInputProperty =
         DependencyProperty.Register("JustPositivDecimalInput", typeof(bool),
         typeof(TextBoxInputBehavior), new FrameworkPropertyMetadata(false));

        public bool JustPositivDecimalInput
        {
            get { return (bool)GetValue(JustPositivDecimalInputProperty); }
            set { SetValue(JustPositivDecimalInputProperty, value); }
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.PreviewTextInput += AssociatedObjectPreviewTextInput;
            AssociatedObject.PreviewKeyDown += AssociatedObjectPreviewKeyDown;

            DataObject.AddPastingHandler(AssociatedObject, Pasting);

        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.PreviewTextInput -= AssociatedObjectPreviewTextInput;
            AssociatedObject.PreviewKeyDown -= AssociatedObjectPreviewKeyDown;

            DataObject.RemovePastingHandler(AssociatedObject, Pasting);
        }

        private void Pasting(object sender, DataObjectPastingEventArgs e)
        {
            if (e.DataObject.GetDataPresent(typeof(string)))
            {
                var pastedText = (string)e.DataObject.GetData(typeof(string));

                if (!this.IsValidInput(this.GetText(pastedText)))
                {
                    System.Media.SystemSounds.Beep.Play();
                    e.CancelCommand();
                }
            }
            else
            {
                System.Media.SystemSounds.Beep.Play();
                e.CancelCommand();
            }
        }

        private void AssociatedObjectPreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Space)
            {
                if (!this.IsValidInput(this.GetText(" ")))
                {
                    System.Media.SystemSounds.Beep.Play();
                    e.Handled = true;
                }
            }

            if (e.Key == Key.Back)
            {
                //wenn was selektiert wird dann wird nur das gelöscht mit BACK
                if (this.AssociatedObject.SelectionLength > 0)
                {
                    if (!this.IsValidInput(this.GetText("")))
                    {
                        System.Media.SystemSounds.Beep.Play();
                        e.Handled = true;
                    }
                }
                else if(this.AssociatedObject.CaretIndex > 0)
                {
                    //selber löschen
                    var txt = this.AssociatedObject.Text;
                    var backspace = txt.Remove(this.AssociatedObject.CaretIndex - 1, 1);

                    if (!this.IsValidInput(backspace))
                    {
                        System.Media.SystemSounds.Beep.Play();
                        e.Handled = true;
                    }
                }
            }

            if (e.Key == Key.Delete)
            {
                //wenn was selektiert wird dann wird nur das gelöscht mit ENTF
                if (this.AssociatedObject.SelectionLength > 0)
                {
                    if (!this.IsValidInput(this.GetText("")))
                    {
                        System.Media.SystemSounds.Beep.Play();
                        e.Handled = true;
                    }
                }
                else if (this.AssociatedObject.CaretIndex < this.AssociatedObject.Text.Length)
                {
                    //selber löschen
                    var txt = this.AssociatedObject.Text;
                    var entf = txt.Remove(this.AssociatedObject.CaretIndex, 1);

                    if (!this.IsValidInput(entf))
                    {
                        System.Media.SystemSounds.Beep.Play();
                        e.Handled = true;
                    }
                }
            }
        }

        private void AssociatedObjectPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            if (!this.IsValidInput(this.GetText(e.Text)))
            {
                System.Media.SystemSounds.Beep.Play();
                e.Handled = true;
            }
        }

        private string GetText(string input)
        {
            var txt = this.AssociatedObject;

            int selectionStart = txt.SelectionStart;
            if (txt.Text.Length < selectionStart) 
                selectionStart = txt.Text.Length;

            int selectionLength = txt.SelectionLength;
            if (txt.Text.Length < selectionStart + selectionLength) 
                selectionLength = txt.Text.Length - selectionStart;

            var realtext = txt.Text.Remove(selectionStart, selectionLength);

            int caretIndex = txt.CaretIndex;
            if (realtext.Length < caretIndex) 
                caretIndex = realtext.Length;

            var newtext = realtext.Insert(caretIndex, input);

            return newtext;
        }

        private bool IsValidInput(string input)
        {
            if (input.Length == 0)
                return true;

            switch (InputMode)
            {
                case TextBoxInputMode.None:
                    return true;
                case TextBoxInputMode.DigitInput:
                    return CheckIsDigit(input);

                case TextBoxInputMode.DecimalInput:
                    decimal d;
                    //wen mehr als ein Komma
                    if (input.ToCharArray().Where(x => x == ',').Count() > 1)
                        return false;

                    if (input.Contains("-"))
                    {
                        if (this.JustPositivDecimalInput) 
                            return false;

                        
                        if (input.IndexOf("-",StringComparison.Ordinal) > 0) 
                            return false;

                        if(input.ToCharArray().Count(x=>x=='-') > 1)
                            return false;

                        //minus einmal am anfang zulässig
                        if (input.Length == 1) 
                            return true;
                    }
                   
                    var result = decimal.TryParse(input, validNumberStyles, CultureInfo.CurrentCulture, out d);
                    return result;
                    
                case TextBoxInputMode.PercentInput: //99,999 is zulässig und  nur positiv ohne 1000er Trennzeichen
                    float f;

                    if (input.Contains("-"))
                        return false;
                    //wen mehr als ein Komma
                    if (input.ToCharArray().Where(x => x == ',').Count() > 1)
                        return false;

                    var percentResult = float.TryParse(input, NumberStyles.Float, CultureInfo.CurrentCulture, out f);

                    if (MaxVorkommastellen.HasValue)
                    {
                        var vorkomma = Math.Truncate(f);
                        if (vorkomma.ToString(CultureInfo.CurrentCulture).Length > MaxVorkommastellen.Value)
                            return false;
                    }

                    return percentResult;
                    
                default: throw new ArgumentException("Unknown TextBoxInputMode");

            }
            return true;
        }

        private bool CheckIsDigit(string wert)
        {
            return wert.ToCharArray().All(Char.IsDigit);
        }
    }

    public enum TextBoxInputMode
    {
        None,
        DecimalInput,
        DigitInput,
        PercentInput
    }
Advertisements
Dieser Beitrag wurde unter Behavior - System.Windows.Interactivity veröffentlicht. Setze ein Lesezeichen auf den Permalink.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s