Listbox.click Rückgabewert des zuletzt angeklickten Items

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

Es gibt 24 Antworten in diesem Thema. Der letzte Beitrag () ist von Tommel.

    Listbox.click Rückgabewert des zuletzt angeklickten Items

    Hallo,

    ich habe in einem kleine Forms Programm. Dieses überprüft, welche Excel Dokumente geöffnet sind und listet die Arbeitsblätter in einer Listbox auf.
    Durch Klick auf einen der Einträge in der Listbox wir auch gleich das entsprechende Arbeitsblatt hervorgehoben.

    VB.NET-Quellcode

    1. wkbGewählt = xls_Appl.Workbooks(mstrWkbName(1 + Me.lstWorksheets.SelectedIndex))
    2. wkbGewählt.Worksheets(Me.lstWorksheets.Text).Activate()


    Soweit funktioniert das schon ganz gut. Allerdings kam von dem künftigen Anwender des Programms der Wunsch mehrer Workbooks auswählen zu können. Prinzipiell kein Problem. Ich habe alle Module, die mit der Listbox arbeiten mit Abfrageschleifen so umprogrammiert, dass sie mit dem Multiselect arbeiten können. Das einzige bei dem ich jetzt hänge, ist diese Auswahl und die Aktivierung des zuletzt angeklickten Items der Listbox.

    Dabei soll natürlich auch immer das Worksheet, das zuletzt in der LIste angewählt werden gehighlightet werden und Informationen daraus abgefragt werden. Allerdings wir über den obigen Code immer nur der erste gewählte Eintrag aktiviert.

    Meine Idee wäre jetzt ein Array aus Booleans zu erstellen, die die selected Eigenschaft der Items überprüfen und über einen Vergleich den Index des zuletzt geänderten Items ausgeben. (Falls das jetzt Sinn macht)

    Ich denke das könnte funktionieren, ich wollte aber mal nachfragen, ob es da nicht auch eine elegantere Möglichkeit gibt. Beispielsweise irgendeine Eigenschaft von Listboxen, die man hier abfragen kann und die ich noch nicht gefunden habe.

    Vielen Dank und viele Grüße
    Tommel
    @Tommel Du musst Dir beim Klick-Ereignis das geklickte Item oder dessen Index merken, das ist dann immer das letzte.
    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!
    Hallo,
    danke für die Antworten.
    @WhitePage Das passt nicht ganz. Ich möchte dass der Anwender einen Mulitselect z.B. bei gedrückter STRG Taste machen kann und dann nacheinander die Items 2,5,4,3 anwählen kann und dann jeweils dass zu dem zuletzt gewählten Item passende Worksheet hervorgehoben wird. Das heißt ich bräuchte den Index des jeweils geklickten Items und nicht ein Maximum, oder minimum.
    Der Maximalwert wäre die Lösung, wenn man davon ausgeht, dass der Anwender in jedem Fall von oben nach unten wählt.
    @RodFromGermany genau das möchte ich ja machen. Ich weiß nur leider nicht wie...

    Gruß

    Tommel schrieb:

    genau das möchte ich ja machen
    Gugst Du hier.
    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!
    Danke schon mal,

    ich komm im Moment zwar noch nicht ganz ans Ziel, aber ich hoffe mit etwas Ruhe und Nachdenken wird des schon...
    Ich hab mir den Code in VB übersetzten lassen und als Function in mein Programm eingebaut.

    Solange ich das Multiselect über STRG ausführe kommt der richtige Wert zurück. Wenn ich aber die Auswahl per Shift oder Maus ziehen ausführe ist der Tracker verständlicherweise verwirrt.

    Ich denke ich werde noch einen Counter vorschalten, der zählt, wie viele Selections sich geändert haben und nur für den Fall einer einzelnen Änderung den Rückgabewert ausgibt.

    Tommel schrieb:

    verwirrt
    (Un-)sinnigerweise sind die SelectedItems- und SelectedIndex-Collections permanent sortiert, da ist leider auch kein rankommen. :/
    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,

    ich hätte die nächste Frage. Und zwar funktioniert mein Code zwar, ich bekomme allerdings eine Warnung, die ich nicht zu 100% verstehe.
    Zunächst mal der Code:
    Aufruf

    VB.NET-Quellcode

    1. Private Sub lstWorksheets_Click1(ByVal sender As Object, ByVal e As System.EventArgs) Handles lstWorksheets.Click
    2. Dim intSelIndex As Integer = TrackSelectionChange(Me.lstWorksheets, listBox1_selection)
    3. (...)
    4. End Sub


    Die Function:

    VB.NET-Quellcode

    1. Private Function TrackSelectionChange(lb As ListBox, selection As List(Of Integer))
    2. Dim sic As ListBox.SelectedIndexCollection = lb.SelectedIndices
    3. Dim Rückgabe As Boolean = False
    4. Dim i1 As Integer = 0
    5. For Each index As Integer In sic
    6. If Not selection.Contains(index) Then
    7. i1 = i1 + 1
    8. End If
    9. Next
    10. Dim i2 As Integer = 0
    11. For Each index As Integer In New List(Of Integer)(selection)
    12. If Not sic.Contains(index) Then
    13. i2 = i2 + 1
    14. End If
    15. Next
    16. If i1 + i2 = 1 Then
    17. For Each index As Integer In sic
    18. If Not selection.Contains(index) Then
    19. selection.Add(index)
    20. Return index
    21. Rückgabe = True
    22. End If
    23. Next
    24. For Each index As Integer In New List(Of Integer)(selection)
    25. If Not sic.Contains(index) Then
    26. selection.Remove(index)
    27. Return index
    28. Rückgabe = True
    29. End If
    30. Next
    31. Else
    32. Return -1
    33. End If
    34. If Rückgabe = False Then Return Nothing
    35. End Function


    Da bekomme ich den Warnhinweis, dass nicht in allen Codepfaden ein Wert zurückgegeben würde und das Ergebnis zur Laufzeit NULL werden könnte.

    Mir ist allerdings nicht ganz klar, in welchem Fall das passieren könnte, oder ob ich durch die Art des Aufrufs diesen Fall schon ausgeschlossen habe und die Warnung ignorieren kann. Oder ist das aus diesem Codeausschnitt noch nicht eindeutlig ersichtlich?

    Gruß
    Vielen Dank! Dass nothing nicht geht ist ja eigentlich auch logisch (ich Depp). Hab den ganzen Teil jetzt mal rausgeschmissen und die Function als Integer defniert:

    VB.NET-Quellcode

    1. Private Function TrackSelectionChange(lb As ListBox, selection As List(Of Integer)) As Integer
    2. Dim sic As ListBox.SelectedIndexCollection = lb.SelectedIndices
    3. Dim i1 As Integer = 0
    4. For Each index As Integer In sic
    5. If Not selection.Contains(index) Then
    6. i1 = i1 + 1
    7. End If
    8. Next
    9. Dim i2 As Integer = 0
    10. For Each index As Integer In New List(Of Integer)(selection)
    11. If Not sic.Contains(index) Then
    12. i2 = i2 + 1
    13. End If
    14. Next
    15. If i1 + i2 = 1 Then
    16. For Each index As Integer In sic
    17. If Not selection.Contains(index) Then
    18. selection.Add(index)
    19. Return index
    20. End If
    21. Next
    22. For Each index As Integer In New List(Of Integer)(selection)
    23. If Not sic.Contains(index) Then
    24. selection.Remove(index)
    25. Return index
    26. End If
    27. Next
    28. Else
    29. Return -1
    30. End If
    31. End Function

    Der Warnhinweis hat sich jetzt verändert. Er sagt die Funktion gibt nicht für alle Codepfade einen Wert zurück und fagt, ob eine Return Anweisung fehlt.
    Allerdings wüsste ich nicht, wie hier kein Wert zurückgegeben werden könnte. Ich bekomme für den Fall, dass sich genau eine Selection ändert den INdex der Änderung zurück und in jedem anderen Fall -1. Oder sehe ich das falsch?

    Danke und Gruß
    Ok damit bekomme ich die Warnmeldung weg. Allerdings wäre ja in dem von dir beschriebenen Fall i1 + i2 = 2 und somit würde -1 zurückgegeben, oder?
    Das heißt aber quasi ich kann mir das else sparen und direkt nach der If-Schleife einen Returnwert ausgeben, für den Fall, dass bis dahin noch nichts zurückgegeben wurde. Habe aber gerade festgestellt, dass ich den Counter ohnehin nochmal überdenken muss. Ich laufe da in einen logischen Fehler rein.
    Ok, das heißt sobald ich einen Return mit einer Bedingung versehe muss ich in jedem Fall einen alternativen Returnwert ohne Bedingung angeben, falls die Bedingung nicht erfüllt wird, weil der Compiler nicht wissen kann, dass es unmöglich ist, die Bedingung nicht zu erfüllen.
    Deswegen ist das vermutlich auch nur eine Warnung und kein Fehler, der die Kompilierung des Codes verhindert.

    Tommel schrieb:

    auch nur eine Warnung
    Auch mit Option Strict On passiert dies:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    3. MessageBox.Show(String.Format("{0} {1}", xxx(True), xxx(False)))
    4. End Sub
    5. Private Function xxx(a As Boolean) As Integer
    6. If a Then
    7. Return 17
    8. End If
    9. ' warning BC42353: Die xxx-Funktion gibt nicht für alle Codepfade einen Wert zurück. Fehlt eine Return-Anweisung?
    10. End Function
    11. End Class
    Bilder
    • RetVal.jpg

      23,23 kB, 590×229, 140 mal angesehen
    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,
    vielen Dank das habe ich jetzt verstanden! Strict on kann ich zwar nicht wählen, weil er dann wegen Late Bindings meckert, aber das ist ein anderes Thema!

    Vielen Dank bis hierher auf jedenfall schon mal und auch vielen Dank für die Erklärungen über die eigentliche Problemlösung hinaus an alle!
    Ich verstehe das ganze jeden Tag ein Stückchen besser und lerne noch viel mehr kennen, was ich noch nicht weiß...

    Nochmals Danke und Gruß!
    Die stellen sind folgende:

    VB.NET-Quellcode

    1. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    2. ' Beim Laden der Form wird geprüft, ob Excel läuft.
    3. ' Wenn Excel vorhanden ist wird die Application eingebunden.
    4. Dim pr() = Process.GetProcessesByName("Excel")
    5. If pr.Length = 0 Then ' Prüfung ob Excel bereits vorhanden ist
    6. xls_Appl = New Excel.Application ' Wenn nicht vorhanden, dann wird die Applikation gestartet
    7. Else
    8. xls_Appl = GetObject(, "Excel.Application") ' Wenn vorhanden, dann vorhandenen Prozess verwenden
    9. End If
    10. End Sub


    Hier gibt er mir mit Srtict on folgende Fehlermeldung:
    "Option Strict On" lässt keine impliziten Konvertierungen von Object in Microsoft.Office.Interop.Excel.Application zu.

    Und in der Folge kommt an jeder Stelle an der ich mich auf das Objekt Excel beziehe, z.b.:

    VB.NET-Quellcode

    1. wkbGewählt = xls_Appl.Workbooks(mstrWkbName(1 + intSelIndex))
    2. wkbGewählt.Worksheets(Me.lstWorksheets.Items(intSelIndex).ToString).Activate()


    "Option Strict On" lässt spätes Binden nicht zu.

    Ich wollte das zwar auch komplett über early Bind machen, allerdings wird dann für den Fall, dass Excel bereits geöffnet ist eine neuer Prozess erstellt und ich kann auf die Workbooks des ursprünlichen Prozesses nicht zugreifen. Deshalb die Abfrage am Anfang.

    Wenn du mich hier auch noch aufschlauen kannst, wäre das natürlich grandios (auch wenn das am ursprünglichen Thema vorbei geht)

    Gruß