NumericTextbox - Zahleneingaben einfach gemacht. Update vom 09.07.2014

    • VB.NET
    • .NET (FX) 3.0–3.5

    Es gibt 34 Antworten in diesem Thema. Der letzte Beitrag () ist von us4711.

      NumericTextbox - Zahleneingaben einfach gemacht. Update vom 09.07.2014

      Version 2014-05-12:
      Nun ist die überarbeitete Version der NumericTextBox fertiggestellt, und als Testprojekt beigefügt. In den Grundzügen ist dieses Control seit 2009 in verschiedensten Projekten im Einsatz.
      Die wesentlichste Überarbeitung stellt die Einbindung des Zahlenformates HexaDezimal auf Anregung von @sonne75 dar, sowie das dynamische Ein-/Ausblenden von Properties durch Anstoss von @VB1963 dar.
      Das Control erbt von System.Forms.Textbox, und verfügt über einen integrierten ErrorProvider

      Die erweiterte Funktionalität umfasst:
      • Beschränkung der Eingabe auf bestimmte Zahlenformate.
      • Zahlenformate: Currency, Decimal, HexaDecimal, Custom.
      • Überprüfung Der Eingabe auf zulässige Zeichen entsprechend des Zahlenformates.
      • Definitionssets für jedes Zahlenformat für Minimal und Maximal-Wert. Defaultwerte sind Decimal.MinValue und Decimal.MaxValue.
      • Überprüfung des Eingabewertes auf Einhaltung des Minimum/Maximumbereichs.
      • Der integrierte ErrorProvider zeigt Eingaben ausserhalb des Minimum/Maximum-Bereichs an.
      • Ausblenden der nicht benötigten Definitionssets zur Entwurfszeit anhand des ausgewählten Zahlenformates.
      • Internationalisierung durch Auswahl der aktiven CulturInfo.
      • Property Value as Decimal gibt den eingegenen numerischen Wert zurück.
      • Property Value ist als Standardbindungseigenschaft definiert, und implementiert INotifyPropertyChanged.
      • Bei Datenänderung wird das Event NumericTextBoxValueChanged ausgelöst.
      • Property LeaveOnEnter legte fest, ob bei Betätigung der <Enter>-Taste zum nächsten Contral gewechselt wird.
      • Property BankersRounding implementiert die richtige kaufmännische Rundung auf die angegebene Zahl Dezimalstellen.
      Points of Interest:

      Das Beispielprojekt ist standardmässig mit der Form frmMain als Startform definiert. Dort gibt es einen Zufallsdatengenerator, der eine Tabelle mit 100 Datensätzen füllt.
      Daraus wird Dataset und BindingSource erstellt, an die ein Datgridview gebunden ist.
      Weiterhin sind 4 NumericTextBoxes mit den unterschiedlichen Zahlenformaten über NumericTextBox.Value an die Tabellenspalte Value gebunden.
      Damit kann die Funktionalität zur Entwurfszeit und zur Laufzeit überprüft werden.
      Interessant ist auch das Rundungsverhalten bei der Anzeige.

      Bei der Entwicklung stellte sich heraus, dass die Abfolge der Events bei Eingabe in die Textbox von kritischer Bedeutung ist.
      In der Form frmEvents werden die auftretenden Events in ihrer Abfolge in einer Listbox dargestellt.
      Damit wird klar, warum bestimmte OnKey-Events in der NumericTextBox verwendet werden.

      Ich würde mich weiterhin freuen, wenn Anregungen zur weiteren Verbesserung beitrügen.

      ToDo:
      • Verhalten, wenn über die Datenbindung Daten ausserhalb des Wertebereiches Minimum/Maximum zur Verfügung gestellt werden. siehe Post #26
      • Parsen des Custom-Formates unvollständig.

      //Edit1:
      Der ursprüngliche Beitrag hat bedauerlicherweise einen unfertigen Quelltext verfügbar gemacht.
      Versionskontrollsysteme sind also doch unverzichtbar ...

      //Edit vom 25.05.2014:
      Spoiler anzeigen
      Aktuelle Version: 3.2014.523.381
      Änderungen/Ergänzungen:
      • Überarbeitung des gesamten Codes
      • Wording angepasst
      • Versionierung eingeführt
      • Control als eigenes DLL-Projekt erstellt
      • Neues Event NumericTextBoxNumberFormatChanged
      • String-Konstante eingeführt
      • Category und Description-Attribute bei Properties ergänzt.
      • KeyCheck-, ValueParse und ValueCheck-Methoden sauber getrennt.
      • Smart-Tags eingeführt
      • Geerbte, nicht benötigte Properties ausgeblendet
      • HexDezimale Anzahl Digits auf Int64 einstellbar ausgeweitet
      • Musterform zum Debuggen des Controls


      //Edit vom 26.05.2014
      Ursprungsdownload entfernt, ist fälschlicherweise ein paarmal heruntergeladen worde, sorry.

      //Edit vom 09.07.2014
      Neue Version 3.2014.709.399 mit folgenden Änderungen/Ergänzungen:
      Spoiler anzeigen
      • Beim CustomNumberFormat werden nun die Dezimalstellen richtig erkannt.
      • Neue Properties TextAlignFocused und TextAlignNotFocused bestimmen die Textausrichtung bei Fokuserhalt/Fokusverlust
      • SmartTags entsprechend ergänzt
      • Änderungen bei den Zahlenformaten werden nun auch im Designer sofort angezeigt (über Events)
      • Validierungen und Umwandlungen gestrafft

      Der Download des Beispielprojektes US.Windows.Forms.NumericTextBox19(3.2014.709.399).zip findet sich bei Post#1
      Dateien

      Dieser Beitrag wurde bereits 9 mal editiert, zuletzt von „us4711“ ()

      us4711 schrieb:

      VB.NET-Quellcode

      1. Stop
      What :?:
      Statt MyBase.KeyPress nimm MyBase.KeyUp, das kannst Du die Keys direkt eingeben.
      Case m_NumberDecimalSeparator ==> Case Keys.Decimal
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      @RodFromGermany Keys.Decimal ist gut. Mir war nicht klar, das hier auch die Culture berücksichtigt wird.
      Mybase.KeyUp ist nicht verwertbar, da dieses Ereignis erst NACH Textbox.TextChanged ausgelöst wird. Und gerade in diesem Handler wird 'ne Menge abgearbeitet.
      stop - (schäm) wie schon oben zu @ErfinderDesRades gesagt, falsche Version (zbzcap)(zu blöd zu copy and paste)

      @sonne75
      Hex-Eingabe wird soeben eingearbeitet, da ist doch noch ein wenig Strukturänderung erforderlich.

      An Alle
      Weiss irgendwer, wie man im Propertygrid des Form-Designers bestimmte Propertys dynamisch ausblenden kann, d.h. in Anhängigkeit vom Inhalt anderer Properies?
      Ich stelle mir vor, das dies über irgendwie über

      VB.NET-Quellcode

      1. <Browsable(False)>
      2. <EditorBrowsable(EditorBrowsableState.Never)>

      gehen könnte, aber wie ändere/erstelle ich diese Attribute zur Designzeit?

      Jede Hilfe/Anregung willkommen.

      us4711 schrieb:

      Mybase.KeyUp
      Dann nimm KeyDown, das macht er allerdings vor dem AutoRepeat.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!

      us4711 schrieb:

      Weiss irgendwer, wie man im Propertygrid des Form-Designers bestimmte Propertys dynamisch ausblenden kann, d.h. in Anhängigkeit vom Inhalt anderer Properies?
      schaue einmal in folgende Links hinein:
      codeproject.com/Articles/18092…e-Evaluation-at-Run-and-D
      codeproject.com/Articles/18952…operties-for-PropertyGrid
      vielleicht hilft dir einer davon...
      @VB1963
      Danke für die Links. Staunen: Das klappt wirklich, aber leider nur zur Laufzeit (was ja eigentlich logisch ist).
      Das dahinterliegende Framework ist recht umfangreich, und wäre alleine deswegen für den Einsatz in einem Stand-Allone-Control wegen der zugehörigen DLL unhandlich.
      Aber Danke, habe wieder etwas gelernt.

      us4711 schrieb:

      im Propertygrid des Form-Designers bestimmte Propertys dynamisch ausblenden kann, d.h. in Anhängigkeit vom Inhalt anderer Properies?
      ich denke das geht wirklich nicht, sonst würde MS das ja selbst nutzen.
      Etwa Textbox.AutoCompleteCustomSource nur einblenden, wenn Textbox.AutoCompleteSource auf .Custom eingestellt ist (wann anders ergibt erstere property keinen Sinn)

      Aber wie man sieht: die kriegens auch net hin, im Designer.
      @ErfinderDesRades, @VB1963

      Die Links haben mir keine Ruhe gelassen, und so habe ich mich in die Untiefen von Reflection begeben. Und siehe da, es geht doch.
      Das beigefügte Projekt zeigt anhand einer beerbten Textbox mit eigenen Properties, wie dynamisches Ein/Ausblenden dieser Properties zur Entwurfszeit möglich ist.

      Ist aber schon ziemlich aufwendig.

      Die verwendete Technik benutzt Standardattribute, hier BrowsableAttribut Funktioniert aber genauso mit den anderen Standards.
      Die Verwenungung von CustomerAttributs führte mich in einen Dschungel, für den mir z.Zt. noch die geeignete Machete fehlt.

      Scheint sehr stabil zu laufen, ich kann auch beim Laufzeitverhalten (wegen Reflection) keine unzumutbaren Einschränkungen erkennen.

      Jetzt kann's auch mit der NumericTextBox weitergehen ...

      Über weitere Ideen würde ich mich freuen.
      Dateien

      ErfinderDesRades schrieb:

      Etwa Textbox.AutoCompleteCustomSource nur einblenden, wenn Textbox.AutoCompleteSource auf .Custom eingestellt ist (wann anders ergibt erstere property keinen Sinn)

      Das von mir vorgeschlagene Verfahren funktioniert auch mit Properties der Basis-Klasse. Hab's im angehängten Projekt für Dein o.a. Beispiel ausprogrammiert.

      Wesentlich ist dabei, dass Du die steuernde Property überlädts, um Zugriff auf deren Setter zu bekommen, um dann dort das gewünschte Verhalten anzustossen.
      Dateien
      Ich sehe, bei falschen Buchstaben im Hexadezimal-Format wird eine Exception ausgelöst. Muss ich sie dann quasi in der Form abfangen und behandeln? Was passiert dann eigentlich? Wird der Code in der Function nicht mehr weiter ausgeführt? Warum hast du es nicht wie andere Falscheingaben behandelt (zu groß, zu klein usw)?
      @sonne75
      Also, ich hab' mir nochmals das in Post#1 beigefügte Beispielprojekt zu Gemüte geführt.
      In frmMain ist die unterste NumericTextBox auf der rechten Seite in den Properties als Zahlenformat:HexaDecimal gekennzeichnet. Und genau das macht die Box auch, wenn Du das Projekt ausführst.
      Insofern kann ich Deine Fehlermeldung nicht nachvollziehen.
      Ist denn in den Properties diser NumericTextBox in der Category NumberFormat HexeDecimal eingestellt?
      Welche Fehlermeldung?? Das war eine Frage zum Code... Function "CheckHexadecimal()" Da wird erst geprüft, ob überhaupt richtiges Format, wenn nicht, gleich Exception ausgelöst. Und dann geprüft, ob in Range, wenn nicht, der Text der Exception in den Setter zurückgegeben und erst da Exception ausgelöst. Und ich habe mich gefragt, warum du es unterschiedlich machst.

      @us4711
      Jetzt habe ich das Projekt ausgeführt, die Zahl im DGV verändert und gleich eine Exception bekommen, dass der Wert nur 4 Stellen lang sein darf...

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „sonne75“ ()

      @sonne75
      It's not a bug, it's a feature.

      Das ist keine Exception, sondern eine Meldung des ErrorProviders, der Dir mitteilt, das der DAU eine nicht den Definitionen entsprechende Eingabe getätigt hat.

      Für die Rahmenbedingungen ist der Programmierer zuständig:
      Im Designer sind die relevanten Properties unter der Category "NumericTextBox" zusammengefasst.
      Dort findest Du einew Property: Numberformat. Wenn diese Auf Currency eingestellt ist, wird eine weiter Property: CurrencyDefinitions eingeblendete.
      Vice Versa, wenn Hexadecimal eingestellt ist, wird die Property HexeDecimalDefinitions angezeigt.
      Klick' auf das Kreuz vor der Property, und schon kannst Du Anzahl der Digits und Maxwert einstellen.

      //Edit:
      Doch noch ein Fehler, aber hat mit dem o.a. Verhalten nix zu tun.
      Bitte so abändern:

      VB.NET-Quellcode

      1. Protected Overrides Sub OnGotFocus(e As EventArgs)
      2. MyBase.OnGotFocus(e)
      3. m_ErrorProvider.SetError(Me, String.Empty)
      4. If Me.NumberFormat = EnumNumericTextBoxNumberFormat.Hexadecimal Then
      5. RefreshTextContents(Me.Value)
      6. Else
      7. Me.Text = Me.Value.ToString
      8. End If
      9. Me.SelectAll()
      10. End Sub

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „us4711“ ()