In Funktion auf Event eines anderen Controls reagieren

  • VB.NET

Es gibt 29 Antworten in diesem Thema. Der letzte Beitrag () ist von Storch.

    In Funktion auf Event eines anderen Controls reagieren

    Hallo Leutz,

    ich hab schon ne Weile recherchiert aber krieg es nicht in meinen Kopf.

    Folgender Codeschnipsel:

    VB.NET-Quellcode

    1. While bClicked = False
    2. Application.DoEvents()
    3. End While


    bClicked wird von einem Button auf True gesetzt, dann wird die Schleife verlassen .
    DoEvents soll aber ziemlich böse sein, daher dachte ich, man müsste doch an der Stelle auf das Clickereignis eines Buttons reagieren könne.
    Ich bekomm es aber einfach nicht hin. Kann mir da jemand einen Tippp geben??
    GUD Uwe

    :whistling: Wenn ich genau wüsste, was ich nicht weiß, dann wäre mein Wissen vollständig!
    Das habe ich auch schon gedacht.

    Es geht um eine selbstgebaute Inputbox. Der Aufruf soll so erfolgen:

    VB.NET-Quellcode

    1. s = uwInputBox(Prompt, Titel)


    Die Funktion stellt einige Werte ein, setzt den Focus in das Eingabefeld und wartet dann auf die EIngabe.
    Mit Ok-Button soll dann übernommen werden.

    Ich müsste die Kontrolle nach dem Focus-setzen abgeben aber die muss ja wieder an die Function zurück, damit der Return zurückgeht.

    Mir schien die Schleife die einzige Möglichkeit
    GUD Uwe

    :whistling: Wenn ich genau wüsste, was ich nicht weiß, dann wäre mein Wissen vollständig!

    Storch schrieb:

    damit der Return zurückgeht.
    Hä?
    Wenn in Deinem Control was passiert, raisest Du ein Event, und das Parent des Controls sollte dies abonieren und dann darauf reagieren.
    Das sieht dann im Prinzip genau so aus wie eine Button-Click-Prozedur.
    Das kannst Du alles im Designer entwerfen.
    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!
    So ...
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private WithEvents test As New TestClass
    3. Private Sub test_InfoChanged(sender As Object, e As TestClass.InfoChangeEventArgs) Handles test.InfoChanged
    4. MessageBox.Show(e.Info)
    5. End Sub
    6. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    7. test.ChangeInfo("Halli Hallo ...")
    8. End Sub
    9. End Class
    10. Public Class TestClass
    11. Public Class InfoChangeEventArgs
    12. Inherits System.EventArgs
    13. Private _info As String
    14. Public ReadOnly Property Info As String
    15. Get
    16. Return _info
    17. End Get
    18. End Property
    19. Public Sub New(info As String)
    20. _info = info
    21. End Sub
    22. End Class
    23. Public Event InfoChanged As EventHandler(Of InfoChangeEventArgs)
    24. Public Sub ChangeInfo(info As String)
    25. RaiseEvent InfoChanged(Me, New InfoChangeEventArgs(info))
    26. End Sub
    27. End Class
    Wenn deine Inputbox funktionieren soll wie die VB.net - Inputbox, dann ist einfach, du mußt sie nur mit .ShowDialog anzeigen, statt mit .Show.

    Hier gibts Übungen mit dem Konzept: Eingabe-Form

    Die Funktion stellt einige Werte ein, setzt den Focus in das Eingabefeld und wartet dann auf die EIngabe.
    Wenn hier die Rede ist von Datensätzen, dann gibts da bessere Konzepte, als alle Daten von einem Datensatz ins Form zu schaufeln, und nach Eingabe wieder zurück.
    Moin moin,

    In #1 habe ich missverständlich ausgedrückt und irgendwie die Event-Geschichte mit der DoEvents-Angelegenheit vermischt. Sorry dafür.

    ich denke, das der Tipp vom @erfinder die beste Lösung ist. ich werd mich jetzt damit mal auseinander setzen. Trotzdem:


    Hier mal meine vollständige Prozedur:

    VB.NET-Quellcode

    1. Public Function uwGetInput(ByVal sPrompt As String, ByVal sTitel As String) As String
    2. 'Eigenschaften einstellen
    3. Me.Text = sTitel
    4. Me.lbl_prompt.Text = sPrompt
    5. Me.uwShow()
    6. Me.txt_backvalue.Focus()
    7. 'OKButton abwarten
    8. While bClicked = False
    9. Application.DoEvents()
    10. End While
    11. 'Wert in Property schreiben
    12. Me.BackValue = txt_backvalue.Text
    13. 'from schließen
    14. Me.uwClose()
    15. 'Property returnen
    16. Return Me.BackValue
    17. End Function


    1. Events

    der von @xtts gepostete ist schon etwas umfangreicher.
    ich hatte eher in die Richtung gedacht, in der While-Bedingung das KLick- Ereignis direkt auswerten zu können, so nach dem Motte While bis Klickereignis eintritt. Also ein Einzeiler. Ist sowas machbar???

    2. DoEVents
    Welche ALternativen gibt es??? Über BackGroundworker hab ich schon was gelesen aber noch nicht sonderlich vertieft. Mir käme das aber für den obigen Zweck doch eher aufwändig vor.
    GUD Uwe

    :whistling: Wenn ich genau wüsste, was ich nicht weiß, dann wäre mein Wissen vollständig!
    Erstell dir mal ein neues Projekt und füg diesem Projekt eine zusätzliche Form (Form2) hinzu. Dann gehst du auf die Form1, machst dir dort nen Button hin und schreibst folgendes rein:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Form2.ShowDialog()
    3. MessageBox.Show("Form2 wurde geschlossen")
    4. End Sub

    Das ist das Prinzip von Form.ShowDialog(). Der Code in dem Button wird erst fortgesetzt, wenn Form2 geschlossen wurde. Genau dasselbe Prinzip kannst du bei dir anwenden, allerdings musst du dann Code etwas abändern.
    Erweitern wir nun also unser Beispiel:
    Du erweiterst nun die Form2 um ein Label, eine TextBox und einen Button und fügst in den Code der Form2 folgenden Code ein:

    VB.NET-Quellcode

    1. Public Class Form2
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. Me.Close()
    4. End Sub
    5. Public Shared Function ShowInputBox(form As Form, text As String) As String
    6. Using dialog As New Form2 'neue Form2 erzeugen
    7. dialog.Label1.Text = text 'Text des Label1 auf den angegebenen setzen
    8. dialog.ShowDialog(form) 'die neue Form2 anzeigen
    9. Return dialog.TextBox1.Text 'wenn sie geschlossen wurde den Text der TextBox1 zurückgeben
    10. End Using
    11. End Function
    12. End Class

    Nun kannst du in deiner Form1 bei dem Button1_Click folgendes einfügen:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Me.Text = Form2.ShowInputBox(Me, "Haaalllooo") 'Me.Text auf das Ergebnis der InputBox setzen.
    3. End Sub

    Ist zwar leider nicht der sauberste Code, kannst du aber sicher als Ansatz nehmen ;).
    Moinsens,

    um den Threed zum Ende zu bringen:

    Der Link von @erfinder hat mich etwas erschlagen, deswegen hab ich erstmal den Code von @nafets getestet. Funktionierte soweit aber bei einer INputbox sollte ja auch auf Abbrechen reagiert werden können.
    Ich kam dann auf die glorreiche Idee, mein schlaues Buch zu konsultieren (sollte ich vllt. öfters machen) und meine lösung sieht jetzt so aus:

    HIer das Form 2 als Inputbox:

    VB.NET-Quellcode

    1. Public Class Form2
    2. Public Sub New()
    3. ' Dieser Aufruf ist für den Designer erforderlich.
    4. InitializeComponent()
    5. ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
    6. Button1.DialogResult = Windows.Forms.DialogResult.OK
    7. Button2.DialogResult = Windows.Forms.DialogResult.Abort
    8. End Sub
    9. End Class

    Hier der Aufruf aus Form1:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    3. Dim f2 As New Form2()
    4. f2.Text = "Eingabe" 'Title
    5. f2.Label1.Text = "Machen Sie Ihre Eingabe" 'Prompt
    6. If f2.ShowDialog() = DialogResult.OK Then Me.TextBox1.Text = f2.TextBox1.Text
    7. 'If f2.ShowDialog() = Windows.Forms.DialogResult.OK
    8. End Sub
    9. End Class

    Zu der remarkierten Zeile 9 eine Frage:
    Wenn ich die Zeile schreibe, schlägt mir Intellisense den Text "Windows.Forms.DialogResult.OK" vor. Warum dieses??? es klappt ja auch die Schreibweise "DialogResult.OK".
    Muss ich da irgendein Imports setzen??? Ich habs mal versucht mit Imports System.Windows.forms versucht aber das hat nix geändert.

    Es klappt aber alles Bestens :) :) :)
    GUD Uwe

    :whistling: Wenn ich genau wüsste, was ich nicht weiß, dann wäre mein Wissen vollständig!

    Storch schrieb:

    Warum dieses???
    Weil der einfach den ganzen Namespace anzeigt, um dann beim Einfügen nur den benötigten Teil zu verwenden.
    Imports System.Windows.forms sind bereits implizit in den Projekteinstellungen vorhanden.
    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!
    Hi @rod,

    IntelliSense fügt aber den gesamten Text auch ein. Also komplett "Windows.Forms.DialogResult.OK". Ich habe es selber auch "DialogResult.OK" verkürzt.
    Ich hatte eigentlich danach einen Fehler erwartet, da ich die vorgeschlagene Schreibweise geändert habe. Es fehlerte aber nicht. Und deswegen Ich = verwirrt.
    Aber wenn es klappt, dann klappt es.

    Und das mit dem Imports war nur ein Versuch, von dem ich eh nicht wirklich glaubte das es klappt, weil, wie Du sagtest, diese schon in den Projekteinstellungen existieren.
    GUD Uwe

    :whistling: Wenn ich genau wüsste, was ich nicht weiß, dann wäre mein Wissen vollständig!
    jo, mir scheint, hast den richtigen Ansatz gefunden.
    Die DialogResults der Buttons kann man auch im FormDesigner festlegen, und sogar beim Form kann man AcceptButton und CancelButton festlegen, und heraus kommt ein Dialog-Form möglicherweise ganz ohne CodeBehind.

    Demnächst mach ich mal ein Tut dazu, mit Video.

    Zur Schreibweise:

    Storch schrieb:

    Aber wenn es klappt, dann klappt es.
    Also dassis die falsche Einstellung - da hast du mehr drauf.
    Wenn was klappt und du weißt nicht warum, dann bist du kurz vor einem Lernschritt - das sollteste nicht verschenken.

    Begründung ist glaub auch schon gesagt worden: Intellisense schreibt meist vollqualifizierten Namen aus, das liest sich umständlich, aber damit liegt sie auf der sicheren Seite.
    Als Programmierer, der seinen Code gut lesbar haben möchte, nutze die Imports - Anweisung, um gewissermaßen die höheren Qualifikationen auszulagern, etwa

    VB.NET-Quellcode

    1. Imports System.Windows.Forms
    Dann langt auch der kurz-qualifizierte Name DialogResult.OK.
    VB bietet auch den besonderen Komfort, projektweite Imports zu setzen, weil etwa in einer WinForms-Anwendung ist wohl sinnvoll, wenn System.Windows.Form in jeder Datei importiert ist.
    Wo wir grad bei projektweiten Imports sind: Standardmäßig ist auch der böse Namespace importiert, den kannman dann auch gleich rausnehmen - gugge böse Funktionen vermeiden
    Hi @erfinder

    natürlich will ich keine Lerneffekte verschenken, sonst hätte ich auch kaum gefragt.
    Und die Erklärung hab ich ja nun zweimal bekommen.

    Ich hatte selbst schon die Idee, durch 'Imports System.Windows.Forms' die Vorschläge von Intellisense abzukürzen.
    Das hat jedoch nicht funktioniert. Ich bekomme trotzdem die Vorschläge vollqualifiziert. Abgesehen davon ist der Verweis ja bereits projektweit eingestellt.

    Wegen den bösen Funktionen..... Auf die hast Du mich an anderer Stelle schon hingewiesen. Seitdem habe ich keinerlei Funktionen mehr verwendet, die ich aus VBA kenne.
    Allerdings hatte ich den Verweis auf 'Microsoft.Visualbasic' nicht entfernt. Das hab ich nun mal nach geholtund festgestellt, das mir dann Konstanten wie 'vbCrLF' etc. nicht mehr zur Verfügung stehen.
    Wie kann ich diese ersetzen, bzw. wo kann ich das nachlesen?
    GUD Uwe

    :whistling: Wenn ich genau wüsste, was ich nicht weiß, dann wäre mein Wissen vollständig!
    Zuweilen geht mir meine Unwissenheit und der Umstand, hier ständig mit Fragen zu nerven, mächtig auf den Sack.

    Ich muss mich erst noch weiter mit den Grundlagen vertraut machen. MS.VB.COntrolChars wird mir nicht unter 'importierte Namespaces' vorgeschlagen.
    Ich habe es mal händisch als Benutzerimport hinzugefügt.. bringt aber nix.. vermutlich auch garnicht der richtige Weg. Auch finde ich System.DateTime nicht.

    Ich neige dazu, für diese kleine Projekt, was ich grad habe, erstmal Ms.VB verweis zu belassen und mich nach und nach durch zu wühlen. Was aber nicht heisst,
    das ich für Hinweise nicht weiter dankbar wäre.
    GUD Uwe

    :whistling: Wenn ich genau wüsste, was ich nicht weiß, dann wäre mein Wissen vollständig!

    Storch schrieb:

    Ich muss mich erst noch weiter mit den Grundlagen vertraut machen. MS.VB.COntrolChars wird mir nicht unter 'importierte Namespaces' vorgeschlagen.
    Ich habe es mal händisch als Benutzerimport hinzugefügt.. bringt aber nix.. vermutlich auch garnicht der richtige Weg.
    Doch, das ist der richtige Weg.
    Wenns nix bringt, vermutlich Schreibfehler.
    Ich hab meine Inputbox jetzt fertig.

    VB.NET-Quellcode

    1. Public Class uwInputBox
    2. Public Sub New()
    3. ' Dieser Aufruf ist für den Designer erforderlich.
    4. InitializeComponent()
    5. ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
    6. cbt_ok.DialogResult = Windows.Forms.DialogResult.OK
    7. cbt_cancel.DialogResult = Windows.Forms.DialogResult.Cancel
    8. End Sub
    9. Public Function GetReturn(ByVal Prompt As String, ByVal Title As String) As String
    10. Me.Text = Title
    11. Me.lbl_prompt.Text = Prompt
    12. Me.txt_backvalue.Text = vbNullString
    13. If Me.ShowDialog = Windows.Forms.DialogResult.OK Then
    14. Return Me.txt_backvalue.Text
    15. Else
    16. Return vbNullString
    17. End If
    18. End Function
    19. End Class


    Aufruf wie folgt:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    2. Dim s As String = uwInputBox.GetReturn("Tünnef eingeben:", "Bockmist")
    3. MessageBox.Show(s)
    4. End Sub


    Ich hab mich entschieden, ShowDialog und das Auswerten von DIalogResult in separater Function mit in die Klasse der Forms zu packen, so kann ich von überall einheitlich drauf zu greifen.
    Ist für andere Anforderungen sicher modifizierbar aber für meine Zwecke scheint es mir ausreichend.
    GUD Uwe

    :whistling: Wenn ich genau wüsste, was ich nicht weiß, dann wäre mein Wissen vollständig!

    Storch schrieb:

    VB.NET-Quellcode

    1. Return vbNullString
    Das bedeutet, du hast den bösen Namespace ja doch noch drinne!
    vbNullString ist eine ganz depperte Konstante, da schreib besser

    VB.NET-Quellcode

    1. Return Nothing

    Da sieht man auch gleich, dass das Ärger geben kann, denn wenn Nothing weiterverarbeitet wird, tritt meist eine NullReference-Exception auf.
    Was natürlich auch beabsichtigt sein kann, denn Nothing ist bei dir ja der Rückgabewert bei User-Abbruch.
    Dann aber teste auch auf Nothing.
    Ich habs grad getestet: Messagebox.Show akzeptiert auch Nothing, und dassis wirklich schlecht. Weil du nun denken mußt, "es klappt", und bei wirklicher Weiterverarbeitung knallts dann.
    zb. probierma

    VB.NET-Quellcode

    1. Dim s As String = uwInputBox.GetReturn("Tünnef eingeben:", "Bockmist")
    2. MessageBox.Show(s.Length)
    und cancel die Eingabe.

    Jedenfalls vbNullString ist eine unnütze Konstante mit Wert Nothing, und da schreib besser gleich Nothing hin, weil da weiß man, wasses ist.
    Und den bösen Namespace wegmachen.
    Der böse Namespace fliegt auch noch raus. Aber eines nach dem anderen.

    Das andere brauch ich nicht mal testen. Das liegt auf der Hand. Mir war auch klar, das ich auf Abbruch prüfen muss, habs nur noch nicht eingebaut.
    Aber Danke für den Tip mit Nothing statt vbnullstring. (Ob das wohl auch unter VBA funzt? mus ich ma testen so aus NEugier)

    Ich gebe jetzt Nothing zurück und der Aufruf sieht so aus:

    VB.NET-Quellcode

    1. Dim s As String = uwInputBox.GetReturn("Tünnef eingeben:", "Bockmist")
    2. If Not s Is Nothing Then
    3. MessageBox.Show(s)
    4. Else
    5. MessageBox.Show("Abbruch")
    6. End If
    GUD Uwe

    :whistling: Wenn ich genau wüsste, was ich nicht weiß, dann wäre mein Wissen vollständig!