Wie bei Laufzeit Button richtig click event setzen

  • VB.NET
  • .NET (FX) 4.5–4.8

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

    Wie bei Laufzeit Button richtig click event setzen

    Hallo,

    schreibe gerade ein kleines Programm, wo für verschiedene Kunden Groupboxen erstellt werden mit jeweils drei Buttons (Excel/PDF/Zng). Man kann Auswählen welche Kunden angezeigt werden sollen und diese Groupboxen/Button werden dann in der Laufzeit erstellt. Das klappt auch alles mit dem erstellen. Die Daten dafür werden aus eine Datatable genommen die ich erstellt habe. Problem wie setze ich hier jetzt am besten die Click Events. Ich mache das mit einer Schleife und hier (DGV_Einstellung_Kunde.Rows(i_dgv).Cells(_dt_kunde_ltl).Value.ToString) ist der Link zum Beispiel für die Exceltabelle abgespeichert. Nur wird der Zähler (i_dgv) nicht mit übergeben. Wie stelle ich das an, das für jeden Kunden der richtige Linke genommen wird.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Sub GB_einzeichnen()
    2. Dim PosX As Integer = 0
    3. Dim PosY As Integer = 0
    4. Dim _grbx As Integer = 95
    5. Dim _grby As Integer = 120
    6. PosX = 10
    7. PosY = 30
    8. For i As Integer = 0 To LB_sichtbar.Items.Count - 1
    9. For i_dgv As Integer = 0 To Me.DGV_Einstellung_Kunde.Rows.Count - 2
    10. If CStr(LB_sichtbar.Items.Item(i)) = (DGV_Einstellung_Kunde.Rows(i_dgv).Cells(_dt_kunde).Value.ToString) Then
    11. _grb = New GroupBox
    12. Controls.Add(_grb)
    13. _grb.Parent = Hauptfenster
    14. _grb.Name = "GB_" + (DGV_Einstellung_Kunde.Rows(i_dgv).Cells(_dt_kunde).Value.ToString)
    15. _grb.Location = New Point(PosX, PosY)
    16. 'If setzen für größe der GB zu bestimmen, Abfrage Link_Sonder im DT
    17. _grb.Size = New Size(_grbx, _grby)
    18. _grb.Text = ""
    19. _la = New Label
    20. Controls.Add(_la)
    21. _la.Font = New Font("Arial", 12, FontStyle.Bold)
    22. _la.Parent = _grb
    23. _la.Name = "L_" + (DGV_Einstellung_Kunde.Rows(i_dgv).Cells(_dt_kunde).Value.ToString)
    24. _la.Location = New Point(5, 8)
    25. _la.Size = New Size(85, 20)
    26. _la.Text = (DGV_Einstellung_Kunde.Rows(i_dgv).Cells(_dt_kunde).Value.ToString)
    27. _la.TextAlign = ContentAlignment.MiddleCenter
    28. _pic = New PictureBox
    29. Controls.Add(_pic)
    30. _pic.Parent = _grb
    31. _pic.Image = My.Resources.Kundenbild
    32. _pic.BackColor = BackColor
    33. _pic.SizeMode = PictureBoxSizeMode.CenterImage
    34. _pic.BorderStyle = BorderStyle.None
    35. _pic.Name = "Pic_" + (DGV_Einstellung_Kunde.Rows(i_dgv).Cells(_dt_kunde).Value.ToString)
    36. _pic.SizeMode = PictureBoxSizeMode.StretchImage
    37. _pic.Size = New Size(85, 50)
    38. _pic.Location = New Point(5, 30)
    39. _b_excel = New Button
    40. Controls.Add(_b_excel)
    41. _b_excel.Parent = _grb
    42. _b_excel.Name = "B_excel_" + (DGV_Einstellung_Kunde.Rows(i_dgv).Cells(_dt_kunde).Value.ToString)
    43. _b_excel.Size = New Size(25, 25)
    44. _b_excel.Location = New Point(5, 85)
    45. _b_excel.BackgroundImage = My.Resources.Excel
    46. _b_excel.BackgroundImageLayout = ImageLayout.Zoom
    47. _b_excel.PerformClick()
    48. AddHandler _b_excel.Click, AddressOf _b_excel_klick
    49. _b_pdf = New Button
    50. Controls.Add(_b_pdf)
    51. _b_excel.Name = "B_pdf_" + (DGV_Einstellung_Kunde.Rows(i_dgv).Cells(_dt_kunde).Value.ToString)
    52. _b_pdf.Parent = _grb
    53. _b_pdf.Size = New Size(25, 25)
    54. _b_pdf.Location = New Point(35, 85)
    55. _b_pdf.BackgroundImage = My.Resources.saveaspdf
    56. _b_pdf.BackgroundImageLayout = ImageLayout.Zoom
    57. _b_zng = New Button
    58. Controls.Add(_b_zng)
    59. _b_zng.Parent = _grb
    60. _b_excel.Name = "B_zng_" + (DGV_Einstellung_Kunde.Rows(i_dgv).Cells(_dt_kunde).Value.ToString)
    61. _b_zng.Size = New Size(25, 25)
    62. _b_zng.Location = New Point(65, 85)
    63. _b_zng.BackgroundImage = My.Resources.sworks
    64. _b_zng.BackgroundImageLayout = ImageLayout.Zoom
    65. Exit For
    66. End If
    67. Next
    68. PosX = PosX + 10 + _grbx
    69. Next
    70. End Sub
    71. 'Das geht so natürlich nicht, habe es mal stehen lassen, damit erkenntlich wird was ich möchte.
    72. Sub _b_excel_klick(ByVal sender As Object, ByVal e As EventArgs)
    73. If Hauptfenster.TBsuchen.Text = "" Then
    74. System.Diagnostics.Process.Start("explorer", (DGV_Einstellung_Kunde.Rows(i_dgv).Cells(_dt_kunde_ltl).Value.ToString))
    75. Else
    76. Hauptfenster.Suchen()
    77. End If
    78. End Sub
    Gegenfrage: Ein DGV käme nicht infrage? Damit wär das schnell erledigt und flexibler für neue Einträge.
    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.
    @VaporiZed Jou.
    @Waxweazle Du hast gerade einen großen Fehler gemacht. ;(
    Du hast eine Herangehensweise vorgegeben, die nicht zu einer guten Lösung Deines Problems führt.
    Fang an und beschreibe Dein Problem verbal, ohne dabei Code zu bemühen.
    Scheib, was Du hast (Informationen aus einer Excel-Tabelle, ...) und was damit getan werden soll, um zu Deinem Ziel zu gelangen.
    Je abstrakter Du das formulierst, um so bessere und elegantere Lösungen bekommst Du hier präsentiert.
    Vielleicht eröffnest Du dazu einen neuen Thread und lässt diesen von der Moderation zu machen, damit hier nicht weiter geantwortet werden kann.
    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!
    Ich würde immer versuchen, es zu vermeiden Controls zur Laufzeit zu erstellen. Lieber per Designer platzieren und sichtbar/unsichtbar schalten.

    Brauche ich aber viele Controls (vielleicht auch noch in variabler Anzahl) der gleichen Art(z.B. Buttons, CheckBoxen, ComboBoxen, schaue ich, ob es hierfür ein Sinnvolles anderes Control gibt, welches die anderen "sammelt". Hier gibt es z.B. CheckedListBox, FlowLayoutPanel oder das sagenumwobene DataGridView.

    Verstehe mich nicht falsch. Dein Lösungsweg ist machbar, aber halt k**** ;) Ich tendiere in deinem Fall, wie die anderen hier scheinbar auch, zum DataGridView.

    Ich finde den Hinweis von @RodFromGermany
    (...)Je abstrakter Du das formulierst(...)
    sehr gut. Je abstrakter du denkst uns beschreibt, desto besser können wir dir helfen.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    @VaporiZed: Meinst oben in der Schleife einfach den Link in ein neues DGV schreiben und dann im Click Event abrufen? Dachte auch schon an so was, wusste aber nicht ob das so elegant ist.

    @mrMo: Mit sichtbar/unsichtbar war meine erste Idee, aber sind zu viele Felder erst mal und später sollen Kunden einfach hinzu gefügt werden können. Das meine Weg nicht der beste ist habe ich mir schon gedacht. Ich habe das Programm ja schon einmal fertig und das war einer meiner ersten Programme. Dies hier habe ich jetzt nochmal neu geschrieben um einfach neue Befehle und Optionen mir bei zu bringen. Ich werde es bestimmt auch eine drittes mal schreiben um einfach zu lernen in welche Variation man alles programmieren kann.

    @RodFromGermany: Ok, versuche es mal ohne Code. In der Firma müssen verschieden Abteilungen immer in gleiche Win-Ordner oder in diesem Win-Ordner Dateien suchen. Das ist natürlich viel geklicke. Ich wollte ein zentrales Programm, mit den wichtigsten Kunden um schnell und einfach ohne Win Explorer in die einzelnen Ordner zu springen oder über ein Suchfeld direkt die Dateien zu suchen und über eine Listbox an zu zeigen. Das ist das Grundkonzept. Da ja neue Kunden hinzu kommen oder entfallen soll das einfach zu erweitern sein. Deswegen möchte ich aus einem selbst gefüllten Datatable (da trage ich Kundenname, die einzelnen Links, usw. ein) "dynamisch" die Kunden einblenden und ausblenden kann. Folgender Vorteil, man kann einfach Kunden neu hinzu fügen.

    @all: Dachte , dass man ein Problem genau erklärt und nicht abstrakt.

    Waxweazle schrieb:

    Dachte , dass man ein Problem genau erklärt
    Du hast erklärt, dass Du mit dem Setzen von Button-Click Probleme hast. ;)
    =======
    OK.
    Das ganze fängt an mit einem ordentlichen Datenmodell, wie der @ErfinderDesRades zu sagen pflegt.
    Bei Dir fängt es an mit einem ordentlichen DataSet, die alle erforderlichen Informationen und Relationen zwischen ihnen enthält.
    Der Rest ist dann tatsächlich mit einem DataGridView und ein wenig Handling erledigt.
    Gugst Du mal hier rein:
    die vier Views auf Video
    Grundlagen: Relationale Datenmodellierung
    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 habe mir die Links angeschaut, und das Prinzip ungefähr davon verstanden. Da ist mir dann eine Frage aufgekommen, benötige ich überhaupt zwei Datatables. In meiner jetzigen steht ja alles drinnen was ich brauche?

    Dann noch eine Verständnisfrage zu dem click-Event was ich angegeben habe. Der Befehl des Button wird ja erst beim klicken auf diesen erstellt oder wird kann der vorher schon angegeben werden? Wenn nicht, müsste ich in dem Klick.Event eine Schleife einbauen auf das DGV mit dem enthaltenen Link?
    Normalerweise setze ich ja im Designer einen Button und setzte ein Click-Event darauf (in dem Fall mit dem Link) und der ist sozusagen jetzt Click mit Button verheiratet (ist nichts besseres eingefallen es zu erklären). Möchte einfach wissen wie das abgearbeitet wird.
    @Waxweazle Du kannst dem DataGridView eine DataGridViewLinkColumn hinzufügen, damit hast Du bereits die halbe Miete drinne.
    Ich hab mal folgendes Beispiel gebaut.
    Ein leeres Datagridview und feddich. Leer, damit die hier im Code stehenden Spalten greifen.
    Teste dies am besten an einem neuen Projekt:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. Dim links As New DataGridViewLinkColumn()
    4. DataGridView1.Columns.Add(links)
    5. Me.DataGridView1.Rows(0).Cells(0).Value = "www.zdf.de"
    6. End Sub
    7. Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick
    8. If e.ColumnIndex = 0 Then
    9. Dim content = DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex).Value
    10. 'MessageBox.Show(content.ToString)
    11. Dim url = New Uri(content.ToString, System.UriKind.RelativeOrAbsolute)
    12. Process.Start(url.ToString)
    13. End If
    14. End Sub
    15. End Class
    Die Uri-Instanz sorgt dafür, dass es egal ist, ob da das http:\\ davor steht oder nicht.
    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: Habe mir dein Beispiel angeschaut. Folgende Fragen Wenn ich eine neue Spalte einfügen will mit DGV.Row.Add() setzt er mir diese immer an erste Stelle an und nicht unten dran. Wie schaffe ich das. Im Spoiler meinen Ansatz. Google finde ich leider nichts.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. Dim links As New DataGridViewLinkColumn()
    4. DataGridView1.Columns.Add(links)
    5. Me.DataGridView1.Rows(0).Cells(0).Value = "c:\"
    6. DataGridView1.Rows.Add()
    7. Me.DataGridView1.Rows(1).Cells(0).Value = "d:\"
    8. End Sub
    9. Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick
    10. If e.ColumnIndex = 0 Then
    11. Dim content = DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex).Value
    12. 'MessageBox.Show(content.ToString)
    13. Dim url = New Uri(content.ToString, System.UriKind.RelativeOrAbsolute)
    14. Process.Start(url.ToString)
    15. End If
    16. End Sub
    17. End Class


    Dann steh ich aber immer noch auf dem Schlauch mit meinen Button. Habe Später sagen wir mal 5x Button Excel, 5x button PDF und 5x Button Zng. Beispiel Excel:
    Button_Kunde_a
    Button_Kunde_b
    Button_Kunde_c
    Button_Kunde_d
    Button_Kunde_e
    Jetzt habe ich in meiner DGV die Positionen der Tabellen:
    c:\Exceltabellen\Kunde-a.xls
    c:\Exceltabellen\Kunde-b.xls
    c:\Exceltabellen\Kunde-c.xls
    c:\Exceltabellen\Kunde-d.xls
    c:\Exceltabellen\Kunde-e.xls
    Jetzt wäre meine Idee eine Schleife zu machen in dem Button.Click-Event wo der Buttonname mit der DGV verglichen wird und der Pfad zugeordnet wird. Klappt mein Gedankengang da überhaupt?
    @Waxweazle Jetzt sollten wir sofort Deine Herangehensweise ändern.
    Pack die Daten in eine DataTable und gib diese dem DataGridView als DataSource.
    Da stimmt die Reihenfolge und die Tabelle kannst Du als XML speichern und laden.
    Sieh Dir mal dieses Beispiel an: Differenz in Prozent ausrechnen
    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: Meinst du meine Standarddaten. Die sind alle in einer Datatable und sind in einem DGV dargestellt. Habe dir mal ein Bild angehängt. Meinst du das? Da sind ja auch alle Links drin. Diese wird auch gespeichert und geladen. Dann werden die Kunden in einer Listbox dargestellt und da kann man auswählen, welche angezeigt werden. und dann die einzelnen Groupboxen mit den jeweiligen Button erstellt.Bis dahin alles gut :)
    Bilder
    • 1.png

      18 kB, 592×389, 103 mal angesehen

    Waxweazle schrieb:

    Meinst du meine Standarddaten.
    Keine Ahnung, das ist doch Dein Projekt.
    Das, was in dem DGV angezeigt wird.
    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!
    Ich werf jetzt mal mein Gedankenbild in den Forenraum:

    Jede Zeile enthält die Kundendaten und einen Excel-Button, der dann eben Excel mit dem Dateipfad öffnet. Da kann man dann noch zig andere Buttons dranhängen, eben für andere Programme. Ist doch ungefähr das, was Ziel ist, richtig? Das hatte ich in Post#2 im Sinn.

    Waxweazle schrieb:

    Dann werden die Kunden in einer Listbox dargestellt und da kann man auswählen, welche angezeigt werden. und dann die einzelnen Groupboxen mit den jeweiligen Button erstellt.
    Was dann hoffentlich überflüssig wird. Schließlich lässt sich die DGV-Anzeige über die BindingSource filtern.
    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.
    @'VaporiZed' Dein Ansatz ist richtig, aber nicht das was ich suche. Finde so ein Lösung später unübersichtlich. Es soll schon eine grafische Oberfläche sein. Wie gesagt das Programm läuft ja schon, schreibe es gerade nur neu um es zu verbessern und neue Feature ein zu bauen. Im Bild habe ich es mal angehangen, Gerade alles ein wenig verschoben, aber man erkennt was ich meine. Ein paar Mitarbeiter sind nicht mehr die Jüngsten und nicht so Fit am PC, da finde ich solche Button mit Bildern übersichtlicher. Brauche ja nur einen Tipp/Idee wie ich das mit den Buttons hin bekomme.

    @RodFromGermany: Ja wird alles eigentlich angezeigt, will ja später einfach per neuer Eingabe in die Datatable einen neuen Kunden hinzufügen. Das ist der Plan.
    Bilder
    • 2.png

      18,83 kB, 711×744, 121 mal angesehen

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Waxweazle“ ()

    Waxweazle schrieb:

    per neuer Eingabe in die Datatable
    Nein.
    Daten werden in das DGV eingegeben, die werden dann automatisch wegen des DataBindings in der DataTable gespeichert.
    Vielleicht machst Du Dir mal ein kleines Testpeojekt mit zwei Buttons und einem DataGridView, Du legst eine DataTable an und weist sie dem DGV als DataSource zu.
    Die beiden Button belegst Du mit Load und Save.
    Damit spielst Du ein wenig rum, bis Du das Verhalten verstanden hast.
    Danach wendest Du dies auf Dein eigentliches Programm an.
    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!
    @Waxweazle OK.
    Gibt es jetzt noch iwelche Probleme?
    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: Ja, also eigentlich immer noch mein Anfangsproblem. Werde es nochmal erklären, denke vielleicht kam es bei meinen alten Erklärungen nicht richtig rüber.
    Ich starte Form1 (Haupform) öffne in dieser eine Form2 (Einstellungen) hier wähle ich aus welche Kunden (Buttons) angezeigt werden sollen, dann wird in der Laufzeit meine Buttons in Form1 erstellt mit dem Code meines ersten Posts. Das funktioniert ja bis dahin. Jetzt ist das Problem, dass meine Button ja noch keine Festlegung haben was sie machen sollen,wenn man sie klickt. Die Information möchte ich aus meine datengebundenen DGV entnehmen.
    Fragen:
    1. Wie mache ich das, wenn man ein Button klickt, dass er das ausführt was ich möchte.
    2. In welche Form muss ich das eintrage (Form1 oder Form2)
    Vorhanden:
    - Der Code für das erstellen in der Laufzeit meiner Buttons
    - DGV mit den erforderlichen Daten für die Buttons.

    Hoffe ich habe es verständlich erklärt, falls noch Infos fehlen sollten, sag mir was du noch für welche bräuchtest.
    @Waxweazle Ich dachte, wir hatten das inzwischen soweit bearbeitet, dass Du auf die selbst erstellten Buttons verzichtest und statt dessen auf die entsprechen de Spalte des DGV klickst.
    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!
    Kurzer Einwurf. Da Du ja wahrscheinlich bei Deinem Design bleiben willst, wäre eine Kombi aus FlowLayoutPanel und UserControl sinnvoll:

    Oder kannst Du Dich mit dem DGV als GUI-Element anfreunden?
    Wenn Du bei Deinem Design bleiben willst, musst Du letztenendes Deine GroupBoxen (oder alternativ bei meinem nicht-DGV-Vorschlag die UserControls) mit der DataTable insofern koppeln, dass immer klar ist, welche(s) GroupBox/User-CE mit welcher DataTable-Zeile gekoppelt ist. Hast Du schon Ideen, wie das vonstatten gehen könnte oder nicht?
    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.