.NET Delete actual files from listbox

2019-08-21 05:40发布

问题:

This code is intended to delete the actual files from the system when it is selected from the system:

Dim file As String()
file = System.IO.Directory.GetFiles("C:\Users\User\Desktop", "lalala.txt", IO.SearchOption.AllDirectories)
If ListBox1.SelectedIndex = -1 Then
    MsgBox("No files selected")
Else
    System.IO.File.Delete(ListBox1.Items(ListBox1.SelectedIndex).ToString())
    ListBox1.Items.RemoveAt(ListBox1.SelectedIndex)
End If

However, only the items in the listbox are deleted. The actual file still exists. I am unsure where I should put the file into the Delete function.

I have referred to this but it has not helped me.

________UPDATE________

I have discovered where it went wrong: it is because only the file name is added to the listbox:

ListBox1.Items.Add(Path.GetFileName(fileFound))

Instead of Path.GetFullPath.

Anyhow, can I delete the file with GetFileName only?

回答1:

The most simple (and reliable) solution would be to create a custom data type and add that to the ListBox instead.

By overriding the ToString() method you can make it display only the file name, while the back-end object still contains the full path.

Public Structure FileEntry
    Public FullPath As String 'A variable holding the full path to the file.

    'Overriding the ToString() method, making it only return the file name.
    Public Overrides Function ToString() As String
        Return System.IO.Path.GetFileName(Me.FullPath)
    End Function

    Public Sub New(ByVal Path As String)
        Me.FullPath = Path
    End Sub
End Structure

Now whenever you want to add paths to the ListBox you've got to add a new instance of the FileEntry structure, instead of a regular string:

ListBox1.Items.Add(New FileEntry(fileFound))

And to delete you just cast the currently selected item into a FileEntry, and then pass its FullPath onto the File.Delete() method.

Dim Entry As FileEntry = DirectCast(ListBox1.Items(ListBox1.SelectedIndex), FileEntry)
System.IO.File.Delete(Entry.FullPath)

NOTE: For this to work every item in the list box must be a FileEntry.

Online test: https://dotnetfiddle.net/x2FuV3 (pardon the formatting, DotNetFiddle doesn't work very well on a cellphone)

Documentation:

  • How to: Declare a Structure (Visual Basic) - Microsoft Docs

  • Overriding the Object.ToString() method - MSDN



回答2:

The problem, as you realised, is that the filename only is not enough information to delete a file. You need the whole path to the file as well. So you need some way of storing the whole path but only showing the filename. This is also important because there might be two (or more) files with same name in separate directories.

A ListBox can have its Datasource property set to show items from "an object that implements the IList or IListSource interfaces, such as a DataSet or an Array."

Then you set the DisplayMember and ValueMember properties to tell it what to display and what to give as the value.

For example, I made up a class named "FileItem" which has properties for the full filename and for whatever you want to display it as, filled a list with instances of "FileItem", and told ListBox1 to display it:

Imports System.IO

Public Class Form1

    Class FileItem
        Property FullName As String
        Property DisplayedName As String

        Public Sub New(filename As String)
            Me.FullName = filename
            Me.DisplayedName = Path.GetFileNameWithoutExtension(filename)
        End Sub

    End Class

    Private Sub PopulateDeletionList(dir As String, filter As String)
        Dim files = Directory.EnumerateFiles(dir, filter, SearchOption.AllDirectories)
        Dim fileNames = files.Select(Function(s) New FileItem(s)).ToList()
        Dim bs As New BindingSource With {.DataSource = fileNames}
        ListBox1.DataSource = bs
        ListBox1.DisplayMember = "DisplayedName"
        ListBox1.ValueMember = "FullName"

    End Sub

    Private Sub ListBox1_Click(sender As Object, e As EventArgs) Handles ListBox1.Click
        Dim lb = DirectCast(sender, ListBox)
        Dim sel = lb.SelectedIndex
        If sel >= 0 Then
            Dim fileToDelete = CStr(lb.SelectedValue)
            Dim choice = MessageBox.Show("Do you really want to delete " & fileToDelete, "Confirm file delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
            If choice = DialogResult.Yes Then
                Try
                    File.Delete(fileToDelete)
                    lb.DataSource.RemoveAt(sel)
                Catch ex As Exception
                    MessageBox.Show("Could not delete " & fileToDelete & " because " & ex.Message)
                End Try
            End If
        End If

    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        PopulateDeletionList("C:\temp", "*.txt")

    End Sub

End Class

Edited I had forgotten to delete the item from the ListBox. To do that, it needs to be tied to the DataSource through a BindingSource.

Extra feature Seeing as there could be more than one file with the same name, you might want to add a tooltip to the listbox items so that you can see which directory it is in. See how to add tooltips on winform list box items for an implementation which needs only minor adjustments to work, such as:

Dim toolTip As ToolTip = New ToolTip()
' ...
Private Sub ListBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles ListBox1.MouseMove
    Dim lb = DirectCast(sender, ListBox)
    Dim index As Integer = lb.IndexFromPoint(e.Location)
    If (index >= 0 AndAlso index < ListBox1.Items.Count) Then
        Dim desiredTooltip = DirectCast(lb.Items(index), FileItem).FullName
        If (toolTip.GetToolTip(lb) <> desiredTooltip) Then
            toolTip.SetToolTip(lb, desiredTooltip)
        End If
    End If
End Sub


回答3:

You can use Path.Combine.

Since you are going to search in C:\Users\User\Desktop, you can do this to delete:

System.IO.File.Delete(Path.COmbine("C:\Users\User\Desktop",ListBox1.Items(ListBox1.SelectedIndex).ToString())

Here, "C:\Users\User\Desktop" and the selected index's text will be combined to make a single path.


Edit:
I get it, you want to show the file name onlyy in the textbox but want to delete the file from the system too but can't do it, right?

Well you can do this:
Put two listbox and while you add a file to a listbox1, put it's path to the listbox2 whose visibility will be False, meaning it won't be shown in the runtime.

DOing this, while an item is selected in the listbox1, use the path.combine to make a path by adding the filename & path from the list with same index number.

Something like this:

    System.IO.File.Delete(path.combine(ListBox1.Items(ListBox1.SelectedIndex).ToString(), ListBox2.Items(ListBox1.SelectedIndex).ToString())