Arbeiten mit der ListView

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

Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von Fakiz.

    Arbeiten mit der ListView

    Hi,

    ich befülle eine ListView wie folgt:

    VB.NET-Quellcode

    1. For Each foundFile As String In My.Computer.FileSystem.GetFiles(strLoadDirectory)
    2. If Not Path.GetExtension(foundFile).ToUpper = ".EXE" Then Continue For 'Skip non .exe file
    3. imgList.Images.Add(Icon.ExtractAssociatedIcon(foundFile))
    4. Dim item As New ListViewItem()
    5. item.Text = Path.GetFileName(foundFile) 'Add filename
    6. item.SubItems.Add(foundFile) 'Add full filename
    7. lvFiles.Items.Add(item).ImageIndex = item.Index 'Add icon
    8. Next


    Das Ergebnis ist ganz annehmbar (s. Anhang)

    Aber natürlich stören mich noch ein paar Kleinigkeiten.

    1. Ich würde die letzte Spalte (die mit dem vollem Pfad) gern verbergen. Ich brauch die Inhalte ... aber ich will das nicht anzeigen.

    2. Und natürlich würde ich dann gern die erste Spalte (die mit dem File Namen) mit dem Attribut "Fill" versehen ... aber auch dafür finde ich keine geeignete Methode.

    3. Ich kann einen Eintrag auswählen. dann erscheint die Zeile blau unterlegt. Aber wie kann ich die Zeile wieder abwählen. Ich hab das wie folgt versucht:

    VB.NET-Quellcode

    1. Private Sub lvFiles_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles lvFiles.MouseDown
    2. 'If e.Button = Windows.Forms.MouseButtons.Right Then lvFiles.ClearSelection()
    3. End Sub


    Aber wie man schon daran erkennt, dass der Befehl auskommentiert ist, klappt das nicht. Die Methode .ClearSelection gibt es nicht ... und ich finde nix, was man anstelle dessen verwenden sollte.

    Kann mir jemand nachsichtig helfen?

    LG
    Peter
    Bilder
    • ListView.jpg

      137,96 kB, 510×247, 179 mal angesehen

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

    jau ... die DatagridView ist eine feine Sache.

    Das blöde ist nur, dass sie halt nicht so elegant Icons darstellen kann. Das ist der große Vorteil der ListView!

    Deshalb suche ich nach einer Lösung für die o.a. Fragen.

    LG
    Peter
    Jau ... klar kann man Icons auch in einer DataGridView darstellen. Man muss das Dingens dazu aber in eine Bitmap umwandeln. Und das ist nicht immer problemlos möglich. Wie im letzten Thread festgestellt.

    Die ListView braucht diese Fummelei nicht ... und dann klappt die Icon Darstellung in jedem Fall.

    Deshalb würde ich gern die Diskussion wieder auf die ListView fokussieren. (Zielorientiert wie ich nun mal bin ... :) )

    Auf die Spalte "FullFilename" kann ich verzichten. Dann muss ich das eben wieder zusammen fummeln ... das sind gerade mal zwei Anweisungen. Aber trotzdem ist dann das Listing immer noch nicht so,wie ich es gern hätte. Ich hab mal die Header Columns wieder sichtbar gemacht, damit man sieht wo das Problem liegt. (s. Anhang)

    Wie man sieht, hat die (einzige) Spalte "Icon" eine feste Länge (nämlich 200). Das habe ich so im Designer eingestellt. Leider kann man da aber nicht "Fill" sagen. Und deshalb sieht die Markierung ein bissl blöde aus.

    Außerdem sehe ich keine Möglichkeit, wie man die Markierung wieder weg bekommt. Was ich halt auch gern hätte.

    Bitte, ich hoffe mir kann jemand dabei helfen !

    LG
    Peter
    Bilder
    • ListView2.jpg

      73,21 kB, 784×246, 167 mal angesehen
    Bleiben wir erst mal bei der ListView ...

    Also die Spaltenbreite an die Breite der Listview anpassen, das kann man ja eigentlich recht einfach:

    VB.NET-Quellcode

    1. lvFiles.Columns(0).Width = lvFiles.Width


    Das Blöde ist halt nur, dass die Sache eine Änderung der Größe der ListView nicht respektiert. D.h. wenn man die Form vergrößert, dann müsste man etwa über das Resize Event die Spaltenbreite nachbessern. Das gefällt mir natürlich auch nicht !

    OMG, ich bin doch nicht der erste Mensch auf diesem Planeten, der mit der Steuerung des ListView Layouts Probleme hat !

    Oder etwa doch ?

    LG
    Peter
    1. Nimm die die zweite Column raus dann ist der Pfad auch weg.

    2. Musst du etwas näher erklären, was meinst du mit 'Attribut "Fill"'?

    3. Das passiert wenn die ListView den Focus verliert. Ansonsten so in der Art wenn MultiSelect = False

    VB.NET-Quellcode

    1. Private Sub listView1_MouseUp(sender As Object, e As MouseEventArgs)
    2. If listView1.SelectedItems.Count > 0 Then
    3. listView1.SelectedItems(0).Selected = False
    4. End If
    5. End Sub



    Das Blöde ist halt nur, dass die Sache eine Änderung der Größe der ListView nicht respektiert

    Selbst ist der Man ;)
    So ziehmlich jedes Control verfügt über den Event Resize welcher ausgelöst wird wenn das Control in der Größe verändert wird, genau hier lässt sich dein Vorhaben implementieren.

    VB.NET-Quellcode

    1. Private Sub listView1_Resize(sender As Object, e As EventArgs)
    2. listView1.Columns(0).Width = (listView1.Width - 5)
    3. End Sub



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

    Gut, die zweite Spalte hatte ich ja schon rausgenommen. Das ist also erledigt.

    Das mit dem Resize hab ich realisiert. Es ist nicht so ganz zufriedenstellend, weil die Breite der Spalte halt nicht nur von der Breite der ListView abhängt, sondern auch davon, ob rechts eine Scroll Bar angezeigt wird oder nicht. Aber das ist marginal.

    Was aber definitv nicht funktioniert, ist das Abwählen der aktuellen Auswahl mit einem Rechtsklick der Maus auf das Control:

    VB.NET-Quellcode

    1. Private Sub lvFiles_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles lvFiles.MouseDown
    2. lblMessage.Text = ""
    3. If e.Button = Windows.Forms.MouseButtons.Right Then
    4. lvFiles.SelectedItems(0).Selected = False
    5. End If
    6. End Sub


    Der Befehl wird ausgeführt

    Danach wird (erwartungsgemäß) die entsprechende Event Routine

    VB.NET-Quellcode

    1. Private Sub lvFiles_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles lvFiles.SelectedIndexChanged


    ausgeführt.

    Und danach ist die Zeile markiert, die ich mit der RECHTEN Maustaste angeklickt habe. Offensichtlich markiert der rechte Mausklick dann gleich wieder neu.

    Ich behelfe mir zur Zeit, indem ich einfach mit der Maus in den freien Bereich neben der ersten (und einzigen) Spalte klicke. Dann ist die Auswahl auch weg.

    Irgendwelche schlauen Ideen?

    LG
    Peter

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

    Es ist nicht so ganz zufriedenstellend

    Dann musst du anstelle der kompletten länge der ListView nur den Client -Bereich der ListView abfragen.

    VB.NET-Quellcode

    1. listView1.Columns(0).Width = listView1.ClientSize.Width


    Zu deinem 2. Problem, mach einen Rechts -Doppelklick (also 2x auf die Rechte Maustaste klicken).
    Okie dokie ... die Eigenschaft .ClientSize.Width behebt dann auch den letzten Schönheitsfehler.

    Jau ... mit einem Doppelclick kann man die Auswahl aufheben. Ich hab mir jetzt einfach einen "Refresh" Button geschrieben, der lädt das Ding neu ... und damit ist die Auswahl auch weg.

    Prima, damit sind alle meine Probleme behoben. Mein Programm läuft rund und fehlerfrei. Ganz herzlichen Dank für deine Ratschläge und deine bemerkenswerte Ausdauer ! Mein Abend ist gerettet ... :)

    LG
    Peter
    Der Doppelclick ist mir nicht "zuviel" ... es geht einfach darum, dass sich meine Anwendungen gleich verhalten. Denn bei ListBoxes und DatagridViews deselektiere ich grundsätzlich mit der rechten Maustaste. Das sollte dann bei einer ListView nicht anders sein.

    Mit dem Event MouseClick klappt das Deselektiern jetzt endlich. Das Anklicken mit der rechten Maustaste selektiert zwar den Eintrag, aber der wird dann durch meine Ereignisroutine postwendend gleich wieder abgewählt. Supi ! Erst mal herzlichen Dank für die nette Idee.

    Vielleicht steinigst du mich jetzt. Aber leider gibt es immer noch einen kleinen Wermutstropfen. Weil die rechte Maustaste den Eintrag erst mal auswählt, bevor er dann deselektiert wird, erscheint die Zeile auf der die Maus beim Rechtsklick zeigt ganz kurz blau unterlegt. Die Markierung dieser Zeile blitzt sozusagen auf bevor sie endgültig verschwindet ... das ist natürlich ein bissl störend. Aber ich fürchte, damit muss man halt leben ... oder fällt dir etwas Gescheites dazu ein ? :)

    LG
    Peter
    Du hast mich schon richtig verstanden. Mit der linken Mause Taste soll das Item selektiert, also blau unterlegt, werden.

    Mit der rechten Maus Taste, soll die Selection wieder aufgehoben werden.

    So wie ich das verstehe, wird per Default zunächst einmal ein Item selektiert, egal ob man die rechte oder linke Maustaste klickt.

    Durch die Ereignisprozeder "MouseClick" kann ich aber dafür sorgen, dass die Selection dann wieder aufgehoben wird.

    VB.NET-Quellcode

    1. Private Sub lvFiles_MouseClick(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles lvFiles.MouseClick
    2. If e.Button = Windows.Forms.MouseButtons.Right Then lvFiles.SelectedItems(0).Selected = False
    3. End Sub


    Das funktioniert ja auch soweit.

    Wenn ich also die rechte Maus Taste bediene, dann passiert folgendes:

    1. vom System wird die aktuelle Selektion aufgehoben und es wird nun die Zeile selektiert, auf welche der Maus Zeiger gerade verweist. Das heißt die Auswahl WECHSELT.

    2. Nun wird die Ereignisroutine "MouseClick" aufgerufen und die neueste Selektion wird per Programmbefehl wieder AUFGEHOBEN. Jetzt ist nix mehr selektiert. Und so war das ja auch beabsichtigt.

    Diesen Ablauf kann man im Debugger nachvollziehen, indem man die Ereignisroutine

    VB.NET-Quellcode

    1. Private Sub lvFiles_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles lvFiles.SelectedIndexChanged


    einfügt.

    Zwischen den Schritten 1 und 2 wird eine Zeile ausgewählt, um dann gleich wieder abgewählt zu werden. Und das führt dazu, dass diese Auswahl kurz aufblitzt. Und das ist nicht erwünscht.

    Hab ich jetzt verständlich machen können wie die Dinge liegen ?

    LG
    Peter

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Peter329“ ()

    Dafür wird eine Variable vom Typ bool nötig. Und am besten eine weitere Methode um Redundanz zu vermeiden. Du brauchst einen bool der symbolisiert ob ein Item selektiert werden darf oder nicht und eine Methode die eventuell selektierte Items wieder deselektiert.
    Im SelectedIndexChange -Event rufst du die Methode auf die das deselektieren übernimmt, diese Methode macht im grunde genommen nichts anderes als zu prüfen ob ein Item selektiert ist und übergibt der Eigenscht .Selected den Wert der bool -Variable die du deklariert hast. Im MouseDown -Event wird die bool -Variable festgelegt, wenn die rechte Maustaste gedrückt ist dann wird die bool -Variable auf false gesetzt und die Methode zum deselektieren wird aufgerufen.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private bClearSelected As Boolean = False
    2. Private Sub listView1_SelectedIndexChanged(sender As Object, e As EventArgs)
    3. ClearSelection()
    4. End Sub
    5. Private Sub listView1_MouseDown(sender As Object, e As MouseEventArgs)
    6. ' Wenn nicht die rechte Maustaste gedrückt wird dann wird die Variable bClearSelected auf false gesetzt
    7. bClearSelected = (e.Button <> System.Windows.Forms.MouseButtons.Right)
    8. ClearSelection()
    9. End Sub
    10. Private Sub ClearSelection()
    11. ' Wenn mindestens ein Item selectiert ist
    12. If listView1.SelectedItems.Count > 0 Then
    13. ' dann wird der Eigenschaft einfach unser wert zugewiesen
    14. listView1.SelectedItems(0).Selected = bClearSelected
    15. End If
    16. End Sub