Steve55 Steve55 - 5 months ago 18
Vb.net Question

How to code a cut operation with a "look and feel" like File Explorer

I need to code a cut operation with the same "Look & Feel" that i see if I perform the same operation in window explorer.

I use visual studio 2008 SP1 (professional and express) on win XP and 7

I have a form with two listview; each listview is in list view and each controls a folder and displays a list of files for that folder. Each row contains the filename with its own icon. the icon is extracted from the file itself and stored in an ImageList control.

Folder display

Cut and Paste operation works fine so my question is about "visual" part. In window explorer when selected files are cut (by contextual menu or CTRL-X) the icons changes to a disabled or no-color state. I wish to perform the same behaviour. I have found the following code:

ControlPaint.DrawImageDisabled(lvwDocFiles.CreateGraphics, _
imgFileIcons.Images(Item.ImageKey), _
Item.Position.X, Item.Position.Y, _
lvwDocFiles.BackColor)


This code works fine and icons will be disabled.

disabled icons

But when I leave the listview to paste on the other listview icons visual state comes back normal.

So, how can I keep the icons disabled until operation has finished?

The code I'm using is a sub called either from mnuCut.Click or CTRL-X keypress

With lvwDocFiles
If .SelectedItems.Count > 0 Then
ClipboardContent = Process.GetCurrentProcess.Id.ToString & STAR & _
(Convert.ToSByte(FilesCopy)).ToString & STAR & _
LinkType.ToString & STAR & _
FolderID.ToString & STAR & _
CodePlantArea.ToString & STAR & _
CodePlantUnit.ToString & STAR & _
CodedDocNumber & STAR & _
NumRev & STAR & _
CodeSender.ToString & STAR & _
FilesPath
For Each Item As ListViewItem In .SelectedItems
ClipboardContent = ClipboardContent & STAR & Item.Name & STAR & Item.Tag.ToString
If Not FilesCopy Then
'IconHeight = imgFileIcons.Images(Item.ImageKey).Height
'IconWidth = imgFileIcons.Images(Item.ImageKey).Width
ControlPaint.DrawImageDisabled(lvwDocFiles.CreateGraphics, _
imgFileIcons.Images(Item.ImageKey), Item.Position.X, _
Item.Position.Y, lvwDocFiles.BackColor)
End If
Item = Nothing
Next Item
Try
Dim LinkFileObject As String = ClipboardContent
Dim LinkFileDataObject As New DataObject(LinkFileFormat.Name, LinkFileObject)
Clipboard.SetDataObject(LinkFileDataObject)
LinkFileDataObject = Nothing
LinkFileObject = Nothing
Catch ex As Exception
Cursor.Current = Cursors.Default
MessageBox.Show(ex.Message, CutOrCopy & " Files", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
End Try
End If
End With

Answer

I want to illustrate the solution I found. The problem was, during a CUT/PASTE operation, visually obtain the same behavior that occurs when the same operation is performed in the file explorer window: display the icons of the items cut in disabled mode. Disabling icons is achieved with the statement:

ControlPaint.DrawImageDisabled(......)

I originally put this statement in the sub who ran the cut operation but the first time that the listview was redesigned icons disabled comes back to their normal display.

Following @Plutonix comment I have realized that redesign of listview must be carried out manually. So at the time when the operation of the CUT starts I do two things:

  1. I store the cut items in a collection CuttedItems; this will serve later in the redesign of listview because the selected items may not be more those cut
  2. I activate the manual redesign with ListView1.OwnerDraw = True

The listview is in view LIST so I need only to code the ListView1.DrawItem event that you can see below:

Private Sub lvwDocFiles_DrawItem(ByVal sender As Object, _
             ByVal e As System.Windows.Forms.DrawListViewItemEventArgs) _
        Handles lvwDocFiles.DrawItem
'
' Identify sender
'
    Dim lvw As ListView = DirectCast(sender, ListView)
'
' Clears background
'
    e.DrawBackground()
'
' Identify item image
'
    Dim itemImage As Image = e.Item.ImageList.Images(e.Item.ImageKey)
'
' Draw item selected or unselected
'
    If e.Item.Selected Then
        e.Graphics.FillRectangle( _
                 SystemBrushes.Highlight, _
                 New RectangleF(e.Bounds.X + itemImage.Width, _
                                e.Bounds.Y, _
                                e.Graphics.MeasureString(e.Item.Text, _
                                lvw.Font, lvw.Width).Width, _
                                e.Bounds.Height))

        e.Graphics.DrawString(e.Item.Text, lvw.Font, _
                              SystemBrushes.HighlightText, _
                              e.Bounds.X + itemImage.Width, _
                              e.Bounds.Y + 2)
    Else
        e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds)
        e.Graphics.DrawString(e.Item.Text, lvw.Font, _
                              SystemBrushes.WindowText, _
                              e.Bounds.X + itemImage.Width, _
                              e.Bounds.Y + 2)
    End If
'
' Draw the image
'
    If CuttedItems IsNot Nothing Then
        If CuttedItems.Contains(e.Item) Then
            ControlPaint.DrawImageDisabled(lvw.CreateGraphics, _
                                           itemImage, _
                                           e.Item.Position.X, _
                                           e.Item.Position.Y, _
                                           lvw.BackColor)
        Else
            e.Graphics.DrawImage(itemImage, _
                                 New PointF(e.Bounds.X, e.Bounds.Y))
        End If
    Else
        e.Graphics.DrawImage(itemImage, _
                             New PointF(e.Bounds.X, e.Bounds.Y))
    End If

End Sub

If the CUT operation is stopped (for example by pressing ESC key or starts an other operation like COPY/PASTE) ListView1.OwnerDraw will be set to False so the redesign of listview will be done as default.

Last note. In redesigning the text of the item I added 2 to e.Bounds.Y. It is a value found by tries. This is because changing OwnerDraw from FALSE to TRUE (and vice versa) I noticed that the text of the item did not stay at the same Y. I can not understand the reason why so I took this "empirical" solution.