DataBinding.Current durch "Autoappend" von Combobox und DBNull durch Textbox löschen

  • VB.NET

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    DataBinding.Current durch "Autoappend" von Combobox und DBNull durch Textbox löschen

    Guten Morgen
    Ich habe ein DataTable mit den Spalen ID / Name / SpalteArtNr und dazu zwei Fragen.
    1.
    Der User kann den Namen über eine gebundene Combobox auswählen. (Databinding über SmartTag, angezeigter Wert = Name, ausgewählter Wert = ID)
    Außerdem habe ich die Combobox so eingestellt, dass Namen automatisch vervollständigt werden (mir fällt der Name der Eigenschaft gerade nicht ein)
    Stellen wir uns vor es gibt die Namen "Tasse" und "Kaffeekanne".
    Wenn die Combobox nun den Wert "Tasse" enthält und ich ersetze diesen Text durch ein "K", wird mir die Combobox automatisch mit "Kaffeekanne" vervollständigt.
    Aber die Bindingsource.Current ändert sich erst, wenn die Combobox nicht mehr aktiv ist. Ich hätte gerne eine Änderung, sobald sich der eingetragene Wert der Combox ändert.
    Gibt es hier eine Möglichkeit dies im Designer zu erledigen, oder muss ich da mit Code ran?

    2.
    Neben dieser Name Combobox gibt es eine Textbox "SpalteArtNr", in der eine Integer gespeichert wird.
    Diese möchte ich löschen können. Also wenn dort z.B. 2 steht, möchte ich durch löschen dieser Zahl den Wert im DataSet auf DBNull setzen.
    Allerdings kann ich die Textbox nicht mehr verlassen, sobald ich dort einen nicht Integer Wert eintrage.
    Gibt es hier auch eine Designerlösung, oder muss ich da mit Code ran?
    1.

    DerSmurf schrieb:

    Aber die Bindingsource.Current ändert sich erst, wenn die Combobox nicht mehr aktiv ist.
    Bei mir ändert sich der DataTable-Wert, sobald ich meine Eingabe mit Enter bestätige. Das ist eine Möglichkeit, die "Validation" anzufordern, was dann die validen Daten in die DataTable schreibt. Ansonsten - wie Du selber schon rausgefunden hast - geschieht das durch Verlassen der TextBox. Das Schreiben des Textes allein reicht für die "Validation" nicht.

    2. Nein, ohne tricky Code ist da m.E. nix möglich.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Nur zu 1.:

    1a) Comboboxen sind im Grunde konzeptionelle Fehlkonstruktionen.
    Es ist Unfug, Auswahlfunktionalität mit Freitext-Eingabe kombinieren zu wollen.

    Was soll das?
    Ich habe "Hans" und "Peter" zur Auswahl.
    Was zum Kuckuck haben die sich gedacht, soll passieren, wenn ich "Walter" eingebe?
    Das ist doch konzeptioneller Bockmist, odr?

    1b) Das Feature mit dem Vervollständigen heisst AutoCompletion.
    Auch ein schönes Konzept, aber auch nicht zum Auswählen zu verwenden.
    AutoCompletion trägt bekannte Vorschläge ein, wenn man aber was abweichendes einträgt, ist das auch gültig.



    Was man braucht ist eine "erzwingende Autovervollständigung" - alias "coercing AutoCompletion"".
    Also wenn du was eintippst, kriegst du Vorschläge, und du kannst nur das eintippen, was mindestens einem der Vorschläge entspricht.
    Habich gecodet, ist ein ziemliches Monster an Logik für nötig:
    codeproject.com/Articles/897961/Coercing-AutoCompletion
    oder glaub besser: AutoCompletion advanced

    (Ach - letzteres ist auch Bestandteil meiner WinFormhelpers)

    Aber guck dir auch den codeproject-Artikel an - da bringe ich imo interessante Sichtweisen zum Thema "Auswahl aus grossen Datenmengen".

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Hallo ihr beiden.
    Danke für eure - wie immer hilfreichen - Antworten.

    Also erstmal zu 2.
    Ich war mir sicher den "Tricky Code" bereits vor meinem Eröffnungspost zu kennen.
    Aber - klappt nicht. Ich wollte im TextChange Event der Textbox prüfen, ob ein Leerstring enthalten ist.
    Wenn ja, Doppelcast auf die entsprechende Bindingsource und anschließend ein SetclmArtNrNull().
    Aber das löst eine Exception aus, die nur im Überwachungsfenster für die DataRow angezeigt wird (das Programm läuft aber weiter), aber ich kann dann die entsprechende Textbox wieder erst verlassen, wenn ich eine Zahl eingebe - bringt also nix...
    Daher habe ich nun aus der Deklaration als int32 einen String gemacht - er kann ja leer sein.
    Diese Konvertiere ich dann im Code als integer. Damit kein mist angegeben werden kann habe ich alle nicht Zahlen Eingaben unterbunden:

    VB.NET-Quellcode

    1. Select Case e.KeyCode
    2. Case Keys.D0 To Keys.D9, Keys.NumPad0 To Keys.NumPad9, Keys.Back, Keys.Delete
    3. Case Else
    4. e.SuppressKeyPress = True
    5. End Select

    Auch irgendwie unschön, da ja hierdurch auch der Wert nach löschen der Textbox nicht DBNull, sondern "" ist - aber mir viel nix anderes ein. - Diese eine Textbox, bzw. dieser eine DataRow Wert, muss leer sein können und "" kann ich ja als leer abfragen.

    zu 1. viele Dank @Erfinderdes für die Links und deine dortige ausführliche Beschreibung.
    Aber ich kann mir vorstellen, dass dies etwas zu "KanonAufSpatzen" ist (bin mir aber nicht sicher).
    Es handelt sich um ca. 70 Einträge in meiner Combobox. Wenn der User einen Wert eingibt, der nicht im DataSet enthalten ist, verkraftet mein Code das auch.
    Nach Vaporizeds Satz:

    VaporiZed schrieb:

    Bei mir ändert sich der DataTable-Wert, sobald ich meine Eingabe mit Enter bestätige. Das ist eine Möglichkeit, die "Validation" anzufordern

    kam mir die Idee einfach im TextChange Event der Combobox ein

    VB.NET-Quellcode

    1. ​Me.Validate()
    auszuführen.
    So habe ich durch die Autovervollständigung, die korrekten Werte in meiner Art.Nr. Spalte Textbox
    Zu 1
    Guck mal, ob du den Kram in deine Helpers hast.
    Wenn ja, ists ja ein Kinderspiel, eine bestehende Combobox mit meim dolle CoercingAutoCompletion auszustatten (2 Zeilen - siehe VB-Tut).
    Dafür braucht man im Form-Designer keine Veränderung an iwelchen Controls vorzunehmen - einfach die bestehende Combo der CoercingAutoCompletion übergeben - die kümmert sich dann.

    Zu 2
    Ich hab grade wie folgt einer Textbox beigebracht, einen Leerstring als NullValue zu akzeptieren:

    VB.NET-Quellcode

    1. Public Sub New()
    2. InitializeComponent()
    3. Col1TextBox.DataBindings("Text").NullValue = ""
    4. End Sub
    Col1 ist eine Int-Spalte im angebundenen Dataset.
    Hallo lieber @ErfinderDesRades
    Ich glaube du hast 1. und 2. vertauscht - daher klemme ich mir die Nummerierung jetzt mal.

    Zur Combobox:
    Nein, den "Kram" finde ich in meinem HelpersSmallEd nicht.
    Aber wie gesagt, mit der jetzigen version kann ich gut leben.
    Wenn der User eine Firma eingibt, die es gar nicht gib, passt das Verhalten des codes - der diese Eingabe ausliest - zum restlichen Verhalten. Also es passiert das gleiche, als wenn ich eine existente, aber falsche Firma, eingebe.
    Also ist in diesem Punkt alles gut, wenn Me.Validate im TextChange Event einer ComboBox vertretbar ist.

    Zur Textbox und Speicherung von DBNull in meiner Int Spalte im DataTable:
    Dein Code funktioniert natürlich. Aber beim rumtesten damit, haben sich mir noch ein paar Fragen gestellt:
    - Wenn ich InitializeComponent() im Public Sub New auskommentiere, kann ich mein Programm nicht starten.
    Visual Studio verhält sich dann, als würde ich ein Programm starten, welches einen Fehler enthält.
    Allerdings wird mir kein Fehler angezeigt. Was ist das?
    - Warum Public Sub New? - wenn ich nur das Col1TextBox.DataBindings("Text").NullValue = "" ins Form Load Event der Hauptform (welche dieses Control enthält) packe - also auch ohne die Initialisierung, klappt das ganze ebenfalls.
    Warum hast du hier Public Sub New gewählt?
    - mit diesem Code "sagst" du doch dem Programm eigentlich auch nur -"wenn kein Wert eingegeben, dann "" "
    Warum funktioniert dies nicht, wenn ich es im Designer bei NullValue festlege?

    DerSmurf schrieb:

    - Wenn ich InitializeComponent() im Public Sub New auskommentiere, kann ich mein Programm nicht starten.
    Visual Studio verhält sich dann, als würde ich ein Programm starten, welches einen Fehler enthält.
    Allerdings wird mir kein Fehler angezeigt. Was ist das?

    Visual Studio schrieb:

    warning BC40054: '"Public Sub New()" im vom Designer generierten Typ "Form1" sollte die InitializeComponent-Methode aufrufen.
    sonst weiß das Programm gar nicht, was alles für CEs erstellt und modifiziert werden sollen.

    DerSmurf schrieb:

    - Warum Public Sub New? - wenn ich nur das Col1TextBox.DataBindings("Text").NullValue = "" ins Form Load Event der Hauptform (welche dieses Control enthält) packe - also auch ohne die Initialisierung, klappt das ganze ebenfalls.
    Tu das. Ich lass die Finger von der Form-New-Prozedur, solange es auch anders geht.

    DerSmurf schrieb:

    - mit diesem Code "sagst" du doch dem Programm eigentlich auch nur -"wenn kein Wert eingegeben, dann "" "
    Warum funktioniert dies nicht, wenn ich es im Designer bei NullValue festlege?

    Wenn Du meinst, dass Du es in der DataTable hinterlegen willst: Weil Du mit anderen Objekten hantierst. In der DataTable wird eine Typprüfung vorgenommen. Wenn Du in ner Int32-Spalte bei NullValue (Empty) oder (Nichts) oder "foo" festlegst, wird das abgelehnt, weil das keine zulässigen Int32-Werte sind.* Klar, man kann Nothing einer Int32-Variable zuordnen. Aber was macht der Compiler draus? Null (also nicht das C#-Pendant zu Nothing, sondern die Zahl 0).
    Die DataBinding-Property der TextBox hingegen kann einen alternativen Wert haben, wenn der dahinterliegende Wert DBNull ist. Gugst Du MSDN-Beitrag.
    Das könntest Du auch hier manipulieren/ändern:


    * bei ner String-Column geht das. Denn da wird dann String.Empty oder Nothing zurückgegeben.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    DerSmurf schrieb:

    Ich glaube du hast 1. und 2. vertauscht
    nee - ich glaub nicht.
    Mit 1. ist doch das Problem gemeint, dass eine Combobox keine vernünftige AutoCompletion anbieten kann?
    Jo, genau das ist in meine WinformHelpers gelöst.
    Ja, inne HelpersSmallEd ists nicht drinne.



    Nochmal zu Sub New() und InitializeComponents():
    Wenn du im Form-Designer dein Form anguckst, dann siehst du da ja die Controls.
    Das ist nur möglich, weil der Designer im Hintergrund InitializeComponents() ausführt.
    Oder anders: Wenn du im Designer ein Control aufs Form schmeisst, so generiert der Designer den ErstellungsCode für dieses Control in die Methode InitializeComponents().
    Dann ruft er sie auf - und siehe: Dein Control ist da.

    Und zur Laufzeit wird dieselbe Methode InitializeComponents() ausgeführt, nämlich in Sub New() des Forms.
    Wenn du keine Sub New() (alias "Konstruktor") gecodet hast, wird eine verborgene Sub New() aufgerufen, die eben auch nix anners macht als: InitializeComponents() aufrufen.
    Langeredekurzesinn: in InitializeComponents() werden die Controls gebaut, deshalb muss die im Konstruktor aufgerufen werden (übrigens auch Komponenten, wie BindingSources etc. - deshalb heisstes "InitializeComponents", und nicht: "InitializeControls").
    Nachdem InitializeComponents() aufgerufen ist, sind die Controls da - vorher sind sie nicht da.
    Also der früheste Zeitpunkt, wann ich meinen eigenen InitialisierungsCode an iwelchen Controls ausführen kann ist, nachdem InitializeComponents() durchgelaufen ist.
    Jo - und so steht das eben in meim Code: nach dem Aufruf von InitializeComponents() kommt mein eigener InitialisierungsCode (wo ich zB das im Designer gesetzte Binding einer Textbox nochmal modifiziere).

    Aber wenn dir das Form_Load-Ereignis lieber ist, kannste deinen InitialisierungsCode auch da unterbringen, weil Form_Load erfolgt ebenfalls sehr früh im Startup eines Forms - ebenfalls lange bevor es anzeigt.
    Bei mir jdfs. hats Fälle gegeben, wo Form_Load nicht so geeignet war, und danach habich mir angewöhnt, im Konstruktor zu initialisieren, und das Form_Load wegzulassen.



    Wie dem auch sei: Freut mich ungeheuerlich, dass du nachfragst, da sehe ich, dass jmd. sich mit meim Kram auseinandersetzt, und davon in seinen Fähigkeiten profitiert - nicht nur in seim Programm, wasser grad codet.

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „ErfinderDesRades“ ()

    ErfinderDesRades schrieb:

    DerSmurf schrieb:
    Ich glaube du hast 1. und 2. vertauscht

    Stimmt, nicht du hast 1. und 2. vertauscht, sondern ich wars.

    ErfinderDesRades schrieb:

    Wie dem auch sei: Freut mich ungeheuerlich, dass du nachfragst, da sehe ich, dass jmd. sich mit meim Kram auseinandersetzt, und davon in seinen Fähigkeiten profitiert - nicht nur in seim Programm, wasser grad codet.

    Gerne :o) Aber irgendwie selbstverständlich, denn zum einen sollen sich die Helfer hier ja die Mühe nicht umsonst - oder eben für ein Projekt machen - sondern damit ich irgendwann auch mal einen "gescheiten" Wissensstand erreiche (und aufhöre euch wegen jedem Mist aufn Sack zu gehen :)

    @VaporiZed ich meine genau diese Designereinstellung auf deinem Screenshot.
    Allerdings habe ich nicht herausgefunden, was ich in einer Int32Spalte als NullWert angeben muss, damit ich eine getätigte Eingabe löschen kann. Weil ich auch sonst weiter nix im Netz gefunden habe, bin ich einfach davon ausgegangen das es nicht geht.

    Zum Public Sub New - da bringt ihr mich jetzt aber in eine doofe Situation.
    @VaporiZed sagt lass es weg und hau die Codezeile ins Form Load
    @ErfinderDesRades sagt, es soll(te) in den Konstruktor, weils im Form Load problemchen (wenn nicht jetzt, dann später) geben könnte.
    Und außerdem ist es wurscht, ob ich Sub New und InitializeComponents() dahin schreibe, weil es passiert ja so oder so.

    Nu weiß der Anfänger nicht, was er tun soll xD
    ist vollkommen egal.
    Das einzige was zu beachten ist: Wenn du Sub New() verwendest, dann muss die unbedingt InitializeComponents() aufrufen.

    Ich meinte übrigens nicht, dasses bei Form_Load Problemchen geben kann, sondern ich persönlich hatte eine besonders anspruchsvolle Initialisierung anne Backe, die günstiger in Sub New angelegt war.
    Und danach habichs mir halt so angewöhnt.