myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
   » Plugin für Firefox
   » Plugin für IE
   » Gadget für Windows
» Regeln
» Wie poste ich richtig?
» Datenschutzerklärung
» wbb-FAQ

Mitglieder
» Liste / Suche
» Stadt / Anleitung dazu
» Wer ist wo online?

Angebote
» ASP.NET Webspace
» Bücher
» Zeitschriften
   » dot.net magazin
» Accessoires

Ressourcen
» .NET-Glossar
» guide to C#
» openbook: Visual C#
» openbook: OO
» .NET BlogBook
» MSDN Webcasts
» Search.Net

Team
» Kontakt
» Übersicht
» Wir über uns
» Bankverbindung
» Impressum

» Unsere MiniCity
MiniCity
» 10 Jahre myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Knowledge Base » FAQ » [FAQ] In einer TextBox nur bestimmte Zeichen/Eingaben zulassen
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | An Freund senden | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

[FAQ] In einer TextBox nur bestimmte Zeichen/Eingaben zulassen

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
herbivore
myCSharp.de-Team (Admin)

images/avatars/avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 48.488
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist online

[FAQ] In einer TextBox nur bestimmte Zeichen/Eingaben zulassen

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Community,

hier findet ihr (mehr als) eine Antwort für die Aufgabe "in einer TextBox nur bestimmte Zeichen zulassen", "in TextBox nur gültige Eingaben erlauben" oder "Eingabe einer TextBox prüfen".

Ich habe mich hier schon öfter im Forum zu diesen Themen geäußert und aus diesen Beiträgen mal folgendes zusammengetragen. Dadurch gibt es zwar ein paar Wiederholungen, aber bis zum Ende auch immer wieder neue Aspekte. Dabei habe ich meine Zitate redaktionell leicht überarbeitet:

Zitat:
Oft ist die erste Überlegung, in KeyDown für alle nicht erlaubten Zeichen e.Handled auf true zu setzen. Aber ganz so einfach ist das nicht, weil es ja noch eine ganze Reihe andere Möglichkeiten gibt, ein bestimmtes Zeichen ins Eingabefeld zu bekommen, außer die zugehörige Taste zu drücken.

Eine Möglichkeit wäre die Zwischenablage. Eine andere den Zeichencode per Alt einzugeben. Um ein großes A einzugeben kann man auch folgende machen: NumLock an, Alt drücken, festhalten, Num6, Num5, Alt loslassen. Gibt sicher noch andere Möglichkeiten.

Bis man da alle Möglichkeiten gefunden und abgedichtet hat, ist es doch einfacher und sicherer auf TextChanged zu reagieren.

Zitat:
Auf der anderen Seite ist der Ansatz nur die "richtigen" Zeichen bei KeyDown o.ä. zu zulassen zu restriktiv ist. So werden können z.B. die Cursortasten (und nicht nur die) funktionsunfähig werden.

Zitat:
Meine TextBox macht das quasi anders herum. Erstmal alles zulassen und nur bei Textänderungen gucken, ob sich ein ungewolltes Zeichen eingeschlichen hat. Wenn ja, den vorigen Zustand wiederherstellen. (Leider muss man für diesen vorigen Zustand dann doch wieder an KeyDown/KeyUp lauschen.)

[Code der TextBox am Ende dieses Beitrags]

Weil allerdings jeweils der ganze Text auf ungültige Zeichen abgesucht wird, eignet sich die Box für lange Texte (Multiline) wohl eher nicht.

Zitat:
Die Veränderung einer TextBox im KeyDown-Event verhindern zu wollen, ist ein Kampf gegen Windmühlen. Was nützt es dort ein bestimmtes Zeichen abzufangen, wenn man das Zeichen einfach nur in die Zwischenablage packen und mit Strg-V einfügen muss, um es doch in die TextBox zu bekommen? Und wenn man Strg-V abfängt (Kanonen/Spatzen), dann man man immer noch über das Kontextmenü der TextBox einfügen. Und wenn man das abgefangen hat, kann der Benutzer das Zeichen weiterhin über Alt+Zehnerblock+Zeichencode in die TextBox bekommen. Und wenn man das abgefangen hat, kommen die Benutzer, die mit Handschriftenerkennung oder Spracheingabe arbeiten. Dann muss man auch die entsprechenden Events abfangen.

Fazit: Der Versuch eine TextBox eingabeseitig zu schützen, ist zum Scheitern verurteilt.

Zitat:
Ansonsten kann ich hier nur meine schon öfter vertretene Meinung anbringen, dass es nicht sinnvoll ist, die Eingaben abzufangen, weil es einfach zu viele Möglichkeiten gibt, z.B. wird oft nicht berücksichtigt, dass man auch über die Zwischenablage Text einfügen kann. Und wenn man Strg-V abgefangen hat, stellt man fest, dass man ja Text auch über rechte Maustaste einfügen kann. Wenn man das festgestellt hat, merkt man irgendwann, dass mal über ALT-Nummernblock Zeichen auch über den Zeichencode eingeben kann. Also auf der Eingabeseite anzusetzen, ist heikel. Und selbst wenn man es schaffen sollte, alle Möglichkeiten abzufangen, wer sagt einem, dass es in der nächsten Windows-Version nicht neue Eingabemöglichkeiten gibt, z.B. über Handschriftenerkennung oder Mausgesten.

Eine weitere Gefahr bei der Eingabe anzusetzen, ist zuviel zu verbieten, also auch sinnvolle Aktionsmöglichkeiten zu verhindern. Also z.B. Ctrl-V vollständig zu sperren, obwohl man es nur nun müsste, wenn der eingefügte Text zuviel Zeilen hat.

Also muss man am Ergebnis ansetzen: im TextChanged-Event gucken, ob eine ungültiges Ergebnis vorliegt, und dann den vorhergehenden Zustand wiederherzustellen. Den vorhergehenden Zustand vorher zu sichern ist auch nicht ganz trivial, aber immer noch wesentlich leichter als auf der Eingabeseite anzusetzen. Leider gibt es keinen Event BeforeTextChanged o.ä. mit dem man eine Änderung leicht verhindern könnte.

Eine andere sinnvolle Möglichkeit sehe ich darin, den Benutzer erstmal so viele Zeilen eingeben zu lassen, wie er will und wenn er mehr eingibt, zu verhindern, dass er das Feld verlassen kann, bevor er den Inhalt korrigiert hat (Stichwort: Validating-Event). Eine noch entspanntere Möglichkeit ist, beim Verlassen nur eine Warnung (z.B. per ErrorProvider) auszugeben und wenn der Benutzer OK drückt, die Warnung zu wiederholen und das OK solange zu ignorieren, bis der Inhalt korrigiert ist.

Zitat:
Es gibt zwei Varianten:
1. verhindern, dass der Benutzer überhaupt etwas falsches eingeben kann und
2. den Benutzer eingeben lassen was er will und ihm später ggf. auf die Finger zu klopfen.

Wenn man sich erstmal dazu durchgerungen hat, die erste Variante aufzugeben, findet man in OnValidating durchaus eine elegante Lösung. Und die Probleme im Vergleich zur ersten Variante sind m.E. doch um einiges geringer.

Es gibt übrigens ein Problem bei der ersten Variante, dass meist übersehen wird. Der Benutzer hat - außer über die (oft nicht vorhandene) Online-Hilfe oder das (ebenfalls nicht selbstverständliche) Handbuch - keine Chance herauszufinden, warum er etwas bestimmtes nicht eingeben kann. Es piept halt bestenfalls nur blöd. Bei OnValidating ist es um einiges einfacher ihm in der ohnehin notwendigen Meldung (nicht Fehlermeldung, positives Denken :-) , Informationen zu geben, in welcher Art er seine Eingabe verändern muss.

Bei alle dem sollte man auch noch berücksichtigen, dass während der Eingabe und besonders beim Editieren eines am Ende gültigen Werts oft ungültige Zwischenzustände entstehen können. Wenn man erzwingen will, dass zu jedem Zeitpunkt in der TextBox ein gültiger Wert ist, dann kann dadurch die Eingabe bzw. das Editieren sehr erschwert oder im Extremfall gar verhindert werden. Auch das spricht dafür, den Wert erst beim Verlassen des Feldes (oder noch später) zu prüfen.

Für rein nummerische Eingaben gibt es außerdem das  NumericUpDown-Control und für Eingaben in einem festem Format das  MaskedTextBox-Control.

herbivore

Hier der angekündigte Code (inkl. Verbesserungen von winSharp93):

C#-Code:
using System;
using System.Text;
using System.Windows.Forms;

//*************************************************************
public class AllowedCharsTextBox : TextBox
{
   //----------------------------------------------------------
   private String _allowedChars             = "-0123456789,";
   // Um von einer bestimmten Kultur unabhängig zu sein, kann man statt "-" und "," besser
   // System.Globalization.NumberFormatInfo.CurrentInfo.NegativeSign und
   // System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator
   // verwenden
   private String _lastValidText            = "";
   private int    _lastValidSelectionStart  = 0;
   private int    _lastValidSelectionLength = 0;
   private bool   _validating               = false;

   //==========================================================
   public String AllowedChars
   {
      get { return _allowedChars; }
      set {
         _allowedChars = value;
         Text = Text; //Text von nun ungültigen Zeichen "bereinigen"
      }
   }

   //==========================================================
   public override String Text
   {
      get { return base.Text; }
      set {
         StringBuilder onlyValid = new StringBuilder ();

         foreach (char ch in value) {
            if (_allowedChars.Contains (ch.ToString ())) {
               onlyValid.Append (ch);
            }
         }

         base.Text = onlyValid.ToString ();
      }
   }

   //==========================================================
   protected override void OnTextChanged (EventArgs e)
   {
      if (_validating) {
         return;
      }
      try {
         _validating = true;

         foreach (char ch in base.Text) {
            if (!_allowedChars.Contains (ch.ToString ())) {
               base.Text       = _lastValidText;
               SelectionStart  = _lastValidSelectionStart;
               SelectionLength = _lastValidSelectionLength;
               return;
            }
         }
         _lastValidText = base.Text;
         _lastValidSelectionStart  = SelectionStart;
         _lastValidSelectionLength = SelectionLength;
         base.OnTextChanged (e);
      }
      finally {
         _validating = false;
      }
   }

   //==========================================================
   protected override void OnClick (EventArgs e)
   {
      _lastValidSelectionStart  = SelectionStart;
      _lastValidSelectionLength = SelectionLength;
      base.OnClick (e);
   }

   //==========================================================
   protected override void OnKeyDown (KeyEventArgs e)
   {
      if (base.Text == _lastValidText) {
         _lastValidSelectionStart  = SelectionStart;
         _lastValidSelectionLength = SelectionLength;
      }
      base.OnKeyDown (e);
   }

   //==========================================================
   protected override void OnKeyUp (KeyEventArgs e)
   {
      if (base.Text == _lastValidText) {
         _lastValidSelectionStart  = SelectionStart;
         _lastValidSelectionLength = SelectionLength;
      }
      base.OnKeyUp (e);
   }
}
12.04.2006 11:37 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 8 Jahre.
Der letzte Beitrag ist älter als 8 Jahre.
Antwort erstellen


© Copyright 2003-2014 myCSharp.de-Team. Alle Rechte vorbehalten. 18.04.2014 22:57