The ThumbnailListView control is ideal for such task as creating a file browser similar to Windows Explorer. This topic describes how it can be done.
To accomplish this task, the ThumbnailListItem class will be used to represent file system objects: files, folders, drives, and so on. These items are based on a special object called PIDL.
PIDL stands for pointer to an item identifier list. It can be interpreted as an element of a tree-structured hierarchy of the shell namespace. This hierarchy includes such objects as:
As any tree-like structure, the shell namespace always has a root element called Desktop. Each PIDL stores references to its children and parent PIDLs (if available). This allows to navigate the tree.
In Graphics Mill for .NET, PIDL objects are represented by the Aurigma.GraphicsMill.WinControls.Pidl class. This class has a number of members which allows to navigate the shell namespace, get path to file/folder (if available), and even grab file content.
Each ThumbnailListItem stores a PIDL which can be accessed using the ThumbnailListItem.Pidl property.
Now, you can create a file browser application. This application will provide the following functionality:
To implement such application, create a new Windows Forms application and add the following controls:
After that configure columns for details view as discussed in the Setting Up the Details View topic.
The result will look as follows:
Fig. 1. File Browser application design
The first thing you need to implement is displaying objects of the current folder in the ThumbnailListView control. Every time the user navigates to some folder, all previously displayed items should be removed, and new items should be loaded.
Define a method which will display subitems of a given PIDL.
' Parent PIDL (necessary for the Up button) Private _parentPidl As Aurigma.GraphicsMill.WinControls.Pidl Private Sub JumpToPidl(ByVal pidl As Aurigma.GraphicsMill.WinControls.Pidl) ' Clear all previously displayed items. thumbnailListView1.Items.Clear() ' If pidl is null, it means that we intend to display the root item. ' Otherwise we extract all children and display them. If Not pidl Is Nothing Then ' We need to keep the parent PIDL to be able to implement ability ' to navigate one level up. _parentPidl = pidl.Parent ' Add all children to the control. Dim subPidl As Aurigma.GraphicsMill.WinControls.Pidl For Each subPidl In pidl.Items thumbnailListView1.Items.Add( _ New Aurigma.GraphicsMill.WinControls.ThumbnailListItem(subPidl)) Next Else ' Root item has no parent. _parentPidl = Nothing ' Add the root item. thumbnailListView1.Items.Add( _ New Aurigma.GraphicsMill.WinControls.ThumbnailListItem( _ Aurigma.GraphicsMill.WinControls.StandardFolder.Desktop)) End If End Sub
// Parent PIDL (necessary for the Up button) private Aurigma.GraphicsMill.WinControls.Pidl _parentPidl; private void JumpToPidl(Aurigma.GraphicsMill.WinControls.Pidl pidl) { // Clear all previously displayed items. thumbnailListView1.Items.Clear(); // If pidl is null, it means that we intend to display the root item. // Otherwise we extract all children and display them. if (pidl != null) { // We need to keep the parent PIDL to be able to implement ability // to navigate one level up. _parentPidl = pidl.Parent; // Add all children to the control. foreach (Aurigma.GraphicsMill.WinControls.Pidl subPidl in pidl.Items) { thumbnailListView1.Items.Add( new Aurigma.GraphicsMill.WinControls.ThumbnailListItem(subPidl)); } } else { // Root item has no parent. _parentPidl = null; // Add the root item. thumbnailListView1.Items.Add( new Aurigma.GraphicsMill.WinControls.ThumbnailListItem( Aurigma.GraphicsMill.WinControls.StandardFolder.Desktop)); } }
During initialization (for example, in the Form_Load event handler) call this method and pass the PIDL of the start folder, for example:
JumpToPidl(Aurigma.GraphicsMill.WinControls.Pidl.Create("C:\Temp"))
JumpToPidl(Aurigma.GraphicsMill.WinControls.Pidl.Create(@"C:\Temp"));
Also, you can navigate to standard folders like My Computer:
JumpToPidl(Aurigma.GraphicsMill.WinControls.Pidl.Create( _ Aurigma.GraphicsMill.WinControls.StandardFolder.MyComputer))
JumpToPidl(Aurigma.GraphicsMill.WinControls.Pidl.Create( Aurigma.GraphicsMill.WinControls.StandardFolder.MyComputer));
If you pass null to this method, the Desktop item (root) will be displayed.
In terms of the ThumbnailListView control, item is activated when it is clicked (either single or double click—depends on control and system settings), or when the user selects it and hits the Enter key. It can be interpreted as an attempt to "open" an item. When it happens, the control raises the ItemActivate event.
When working with PIDL-based items, two kinds of items can be distinguished—folders and files. Folders are containers of other PIDLs (and can be empty though). Files never have children, but they have binary content. To determine what the current PIDL is, the Pidl.Type property can be used.
You need to provide two kinds of behavior when items are activated:
To achieve this, add the following ItemActivate event handler:
Private Sub thumbnailListView1_ItemActivate(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles thumbnailListView1.ItemActivate ' Get the PIDL of the item which is in focus. Dim currentPidl As Aurigma.GraphicsMill.WinControls.Pidl = _ CType(thumbnailListView1.FocusedItem, _ Aurigma.GraphicsMill.WinControls.ThumbnailListItem).Pidl If currentPidl.Type = Aurigma.GraphicsMill.WinControls.PidlType.Folder Then ' If this PIDL is a folder, jump to the PIDL of this folder... JumpToPidl(currentPidl) Else '...but if it is a file, attempt to load it into the BitmapViewer Try bitmapViewer1.Bitmap.Load(currentPidl.Stream) Catch ex As Aurigma.GraphicsMill.Codecs.MediaUnsupportedException MessageBox.Show("This file format is not supported!") End Try End If End Sub
private void thumbnailListView1_ItemActivate(object sender, System.EventArgs e) { // Get the PIDL of the item which is in focus. Aurigma.GraphicsMill.WinControls.Pidl currentPidl = ((Aurigma.GraphicsMill.WinControls.ThumbnailListItem) (thumbnailListView1.FocusedItem)).Pidl; // If this PIDL is a folder, jump to the PIDL of this folder... if (currentPidl.Type == Aurigma.GraphicsMill.WinControls.PidlType.Folder) { JumpToPidl(currentPidl); } //...but if it is a file, attempt to load it into the BitmapViewer else { try { bitmapViewer1.Bitmap.Load(currentPidl.Stream); } catch(Aurigma.GraphicsMill.Codecs.MediaUnsupportedException ) { MessageBox.Show("This file format is not supported!"); } } }
Getting Top and Up buttons working is extremely easy. Each of these buttons should make a single call of the JumpToPidl method.
The Top button should pass null:
Private Sub buttonTop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles buttonTop.Click JumpToPidl(Nothing) End Sub
private void buttonTop_Click(object sender, System.EventArgs e) { JumpToPidl(null); }
The Up button should pass the stored parent PIDL:
Private Sub buttonUp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles buttonUp.Click JumpToPidl(_parentPidl) End Sub
private void buttonUp_Click(object sender, System.EventArgs e) { JumpToPidl(_parentPidl); }
The last thing to implement is choice of a view mode. It is also simple. Just change the View property of the control when the user changes the view. In this example, a combo box will be used.
Add four items to the combo box:
Then add the following SelectedIndexChanged event handler:
Private Sub comboBoxViewMode_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles comboBoxViewMode.SelectedIndexChanged Select Case comboBoxViewMode.SelectedIndex Case 0 thumbnailListView1.View = Aurigma.GraphicsMill.WinControls.View.Thumbnails Case 1 thumbnailListView1.View = Aurigma.GraphicsMill.WinControls.View.Icons Case 2 thumbnailListView1.View = Aurigma.GraphicsMill.WinControls.View.List Case 3 thumbnailListView1.View = Aurigma.GraphicsMill.WinControls.View.Details End Select End Sub
private void comboBoxViewMode_SelectedIndexChanged(object sender, System.EventArgs e) { switch(comboBoxViewMode.SelectedIndex) { case 0: thumbnailListView1.View = Aurigma.GraphicsMill.WinControls.View.Thumbnails; break; case 1: thumbnailListView1.View = Aurigma.GraphicsMill.WinControls.View.Icons; break; case 2: thumbnailListView1.View = Aurigma.GraphicsMill.WinControls.View.List; break; case 3: thumbnailListView1.View = Aurigma.GraphicsMill.WinControls.View.Details; break; } }
If you allow changing the view mode in some other place (for example, if you add a pop-up menu), it makes sense to track view mode change to be able to update the combo box properly. To do that, handle the ViewChanged event:
Private Sub thumbnailListView1_ViewChanged(ByVal sender As System.Object, _ ByVal e As Aurigma.GraphicsMill.WinControls.ViewChangedEventArgs) _ Handles thumbnailListView1.ViewChanged Select Case e.NewView Case Aurigma.GraphicsMill.WinControls.View.Thumbnails comboBoxViewMode.SelectedIndex = 0 Case Aurigma.GraphicsMill.WinControls.View.Icons comboBoxViewMode.SelectedIndex = 1 Case Aurigma.GraphicsMill.WinControls.View.List comboBoxViewMode.SelectedIndex = 2 Case Aurigma.GraphicsMill.WinControls.View.Details comboBoxViewMode.SelectedIndex = 3 End Select End Sub
private void thumbnailListView1_ViewChanged(object sender, Aurigma.GraphicsMill.WinControls.ViewChangedEventArgs e) { switch (e.NewView) { case Aurigma.GraphicsMill.WinControls.View.Thumbnails: comboBoxViewMode.SelectedIndex = 0; break; case Aurigma.GraphicsMill.WinControls.View.Icons: comboBoxViewMode.SelectedIndex = 1; break; case Aurigma.GraphicsMill.WinControls.View.List: comboBoxViewMode.SelectedIndex = 2; break; case Aurigma.GraphicsMill.WinControls.View.Details: comboBoxViewMode.SelectedIndex = 3; break; } }