Back to Devexpress

Custom Browsers (FileExplorerAssistant Component)

windowsforms-403431-controls-and-libraries-messages-notifications-and-dialogs-custom-folder-browsers.md

latest17.3 KB
Original Source

Custom Browsers (FileExplorerAssistant Component)

  • Dec 10, 2024
  • 10 minutes to read

The DevExpress WinForms suite ships with skinable counterparts for default WinForms file/folder dialogs: XtraFolderBrowserDialog, XtraOpenFileDialog, and XtraSaveFileDialog. The FileExplorerAssistant component allows you to embed similar functionality in a form or UserControl, and build custom file/folder explorers that can navigate local storage and/or virtual node hierarchy.

Default Folder Browser

This section explains core FileExplorerAssistant concepts and demonstrates how to build the standard file/folder browser similar to Windows Explorer.

Place the FileExplorerAssistant component on a form or UserControl, and invoke its smart-tag menu.

Click the “Add…” actions to add all three browser components:

All parts are default DevExpress controls with FileExplorerAssistant extensions attached to them. Extensions customize the appearance and behavior of controls, and allow these controls to communicate with their parent FileExplorerAssistant component.

Extensions include:

  • GridControl extension (GridControl)
  • TreeList extension (TreeList)
  • Breadcrumb Edit extension (BreadcrumbEdit)
  • Preview Panel extension (PanelControl)

When you click an “Add…” smart-tag menu action, the component creates the corresponding control-extension pair. If needed, you can click the “Edit Extensions” smart-tag menu action to create standalone extensions and bind them to controls on a form or UserControl.

Note

The FileExplorerAssistant loads default settings for attached controls and overrides their settings specified at design time. Specify properties in the Form.Load event handler:

csharp
private void Form1_Load(object sender, EventArgs e) {
  gridView1.OptionsSelection.EnableAppearanceHotTrackedRow = DevExpress.Utils.DefaultBoolean.False;
}
vb
Private Sub Form1_Load(sender As Object, e As EventArgs)
  gridView1.OptionsSelection.EnableAppearanceHotTrackedRow = DevExpress.Utils.DefaultBoolean.False
End Sub

TreeList Extension

The TreeList Extension has the RootNodes collection that specifies the list of top-level nodes. Initially, this collection has only one node — the EnvironmentSpecialFolderNode that allows users to browse one of the special Windows folders: Desktop, My Documents, Program Files, Fonts, and others. The initial value of this node is “Desktop”, which allows users to browse the entire local storage of the current PC.

You can modify this collection to add other nodes:

  • PathNode points to a single local storage folder or drive. The path to this object is stored in the node’s Path property.

  • GuidNode allows you to add special folders that have GUIDs.

  • VirtualFolderNode and VirtualItemNode are custom nodes. You can specify their title and image, and VirtualFolderNodes can be populated with child nodes. Use these nodes to create custom entries that are not present on local storage.

GridControl Extension

The two core settings of the GridControl extension are:

  • ViewMode — allows you to choose between eight Explorer styles (Tiles, Content, Large Icons, and others).
  • CurrentPath — the currently browsed directory.

CurrentPath is the currently browsed directory.

Preview Panel Extension

Integrates a preview pane. With it, users can preview Office-related documents (e.g., DOCX, XLSX, CSV), PDFs, HTML files, text files, and images before opening the actual file.

Run Demo

Connect Extensions

Extensions do not communicate with each other. For example, if a user selects a node inside a TreeList, the Data Grid does not reflect this navigation. You need to implement the communication between extensions based on the structure of your custom folder explorer.

A “navigation binding” is an object of the DevExpress.XtraDialogs.NavigationBinding class. These objects have two properties:

  • Source — specifies a control whose navigation is tracked.
  • Target — specifies a control that should replicate the Source control navigation.

When stored inside the FileExplorerAssistant.NavigationBindings collection, navigation bindings transmit navigation actions from one extension owned by this FileExplorerAssistant component to another.

You can add navigation bindings at design time (click the ellipsis button next to the “NavigationBindings” property in the Visual Studio Property Grid) or in code. At design time, the Collection Editor dialog checks whether both Target and Source properties are set, and highlights bindings that are missing either of these settings.

You can also edit navigation bindings in code:

csharp
NavigationBinding nbGridToBreadcrumb = new NavigationBinding();
nbGridToBreadcrumb.Source = gridControlExtension1;
nbGridToBreadcrumb.Target = breadCrumbExtension1;
fileExplorerAssistant1.NavigationBindings.Add(nbGridToBreadcrumb);
vb
Dim nbGridToBreadcrumb As New NavigationBinding()
nbGridToBreadcrumb.Source = gridControlExtension1
nbGridToBreadcrumb.Target = breadCrumbExtension1
fileExplorerAssistant1.NavigationBindings.Add(nbGridToBreadcrumb)

The following example demonstrates how to bind a Preview Panel extension to Grid Control extension:

csharp
var gridExtension = assistant.Attach(grid, x => {
    x.CurrentPath = initialPath;
});
var previewExtension = assistant.Attach(panel);
assistant.NavigationBindings.Add(new NavigationBinding() { Source = gridExtension, Target = previewExtension });
vb
Dim gridExtension = assistant.Attach(grid, Sub(x) x.CurrentPath = initialPath)
Dim previewExtension = assistant.Attach(panel)
assistant.NavigationBindings.Add(New NavigationBinding() With {.Source = gridExtension, .Target = previewExtension})

Run Demo

Another way to connect extensions is to handle the CurrentItemChanged event available for every FileExplorerAssistant extension. This event fires every time a user selects a different item within a control. Handle CurrentItemChanged if you need to implement a custom extension communication logic that cannot be implemented with navigation bindings.

csharp
private void treeListExtension1_CurrentItemChanged(object sender, CurrentItemChangedEventArgs e) {
    // Update Data Grid and Breadcrumb when the Tree List selection changes
    gridControlExtension1.SetCurrentItem(e.CurrentItem);
    breadCrumbExtension1.SetCurrentItem(e.CurrentItem);
}
vb
Private Sub treeListExtension1_CurrentItemChanged(ByVal sender As Object, ByVal e As CurrentItemChangedEventArgs)
    ' Update Data Grid and Breadcrumb when the Tree List selection changes
    gridControlExtension1.SetCurrentItem(e.CurrentItem)
    breadCrumbExtension1.SetCurrentItem(e.CurrentItem)
End Sub

FileExplorerAssistant extensions expose an API that allows you to manage files and folders. This section demonstrates how to use this API to implement action buttons similar to those seen in the “Two-Panel File Manager” DevExpress demo.

Run Demo: Two-Panel File Manager, XtraDialogs Demo

  • DoDefaultAction — navigates inside the selected folder, or opens the selected file in a default program associated with the file’s extension (Notepad for .txt files, Photos for .png files, and so on).

  • Rename — renames the selected file or folder.

  • CopySelectedItem and MoveSelectedItem — copy or move the selected file or folder to the location specified by the method’s parameter. In the code below the selected file is copied to the currently open folder of another Grid.

  • CreateNewFolder — creates a new directory inside the currently browsed folder.

  • GoBack, GoForward, GoUp — navigation methods.

  • Properties that start with “Can” return whether the corresponding action can be executed for the current folder or file. For instance, if a user browses the SpecialEnvironmentFolder.Desktop, they cannot navigate to the parent folder (the GoUp method is not available), and the CanGoUp property returns false.

  • SetCurrentPath and SetCurrentSpecialFolder — allow you to browse a specific folder or special Windows folder.

Custom Hierarchy

The FileExplorerAssistant component allows you to create solutions that browse not only folders on local storage, but also virtual (custom) hierarchies.

Run Demo: Car Rental Catalogue, XtraDialogs Demo

To create a custom hierarchy for the Tree List control, populate the RootNodes collection of the control’s related extension with VirtualFolderNode and VirtualItemNode instances.

VirtualFolderNode class objects serve as “folders”. These objects have the Nodes collection that you can use to populate them with child folders or items.

csharp
VirtualFolderNode rootNode = new VirtualFolderNode("Root Node");
VirtualFolderNode childNode = new VirtualFolderNode("Child Node 1");
rootNode.ImageOptions.SvgImage = svgImageCollection1[0];
childNode.ImageOptions.SvgImage = svgImageCollection1[1];
// ...
// Add more child nodes
rootNode.Nodes.Add(childNode);
treeListExtension1.RootNodes.Add(rootNode);
vb
Dim rootNode As VirtualFolderNode = New VirtualFolderNode("Root Node")
Dim childNode As VirtualFolderNode = New VirtualFolderNode("Child Node 1")
rootNode.ImageOptions.SvgImage = svgImageCollection1(0)
childNode.ImageOptions.SvgImage = svgImageCollection1(1)
' ...
' Add more child nodes
rootNode.Nodes.Add(childNode)
treeListExtension1.RootNodes.Add(rootNode)

VirtualItemNode class objects serve as “files”. These objects cannot embed other folders or items, and are not shown inside a Tree List (similar to local storage files).

csharp
VirtualFolderNode rootNode = new VirtualFolderNode("Root Node");
rootNode.Nodes.Add(new VirtualFolderNode("Child Node 1"));
((VirtualFolderNode)rootNode.Nodes[0]).Nodes.Add(item1);
vb
Dim rootNode As New VirtualFolderNode("Root Node")
rootNode.Nodes.Add(New VirtualFolderNode("Child Node 1"))
CType(rootNode.Nodes(0), VirtualFolderNode).Nodes.Add(item1)

Combine virtual “folder” and “file” objects to create a custom hierarchy as your needs dictate.

Custom Preview

The following example demonstrates how to preview SVG files:

csharp
using DevExpress.Dialogs.Core.Items;
using DevExpress.Utils.Svg;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Base.Controls.Preview;
using DevExpress.XtraEditors.Controls;
using System.Windows.Forms;

var gridExtension = assistant.Attach(grid, x => {
    x.CurrentPath = initialPath;
    x.FilterString = "Svg files (*.svg)|*.svg";
});
var previewExtension = assistant.Attach(panel, x => {
    x.CustomizePreview += (s, e) => {
        if(e.Item.Extension.ToLower() == ".svg")
            e.CustomPreviewHandler = new SvgPreviewHandler();
    };
});
assistant.NavigationBindings.Add(new NavigationBinding() { Source = gridExtension, Target = previewExtension });
//...
public class SvgPreviewHandler : WinPreviewHandlerBase {
    SvgImage svgImage;

    public override bool Load(string file, ShellItem shellItem) {
        base.Load(file, shellItem);
        bool loaded = false;
        if(shellItem.Extension.ToLower() == ".svg") {
            try {
                this.svgImage = SvgImage.FromFile(file);
                loaded = true;
            }
            catch { }
        }
        return loaded;
    }
    public override Control CreatePreviewControl() {
        var picEdit = new PictureEdit();
        picEdit.SvgImage = svgImage;
        picEdit.Enabled = false;
        picEdit.BorderStyle = BorderStyles.NoBorder;
        picEdit.Properties.SizeMode = PictureSizeMode.Squeeze;
        picEdit.Properties.UseDisabledStatePainter = false;
        return picEdit;
    }
}
vb
Imports DevExpress.Dialogs.Core.Items
Imports DevExpress.Utils.Svg
Imports DevExpress.XtraEditors
Imports DevExpress.XtraEditors.Base.Controls.Preview
Imports DevExpress.XtraEditors.Controls
Imports System.Windows.Forms

Private gridExtension = assistant.Attach(grid, Sub(x)
    x.CurrentPath = initialPath
    x.FilterString = "Svg files (*.svg)|*.svg"
End Sub)
Private previewExtension = assistant.Attach(panel, Sub(x)
    AddHandler x.CustomizePreview, Sub(s, e)
        If e.Item.Extension.ToLower() = ".svg" Then
            e.CustomPreviewHandler = New SvgPreviewHandler()
        End If
    End Sub
End Sub)
assistant.NavigationBindings.Add(New NavigationBinding() With {.Source = gridExtension, .Target = previewExtension})
' ...
Public Class SvgPreviewHandler
    Inherits WinPreviewHandlerBase

    Private svgImage As SvgImage

    Public Overrides Function Load(ByVal file As String, ByVal shellItem As ShellItem) As Boolean
        MyBase.Load(file, shellItem)
        Dim loaded As Boolean = False
        If shellItem.Extension.ToLower() = ".svg" Then
            Try
                Me.svgImage = SvgImage.FromFile(file)
                loaded = True
            Catch
            End Try
        End If
        Return loaded
    End Function
    Public Overrides Function CreatePreviewControl() As Control
        Dim picEdit = New PictureEdit()
        picEdit.SvgImage = svgImage
        picEdit.Enabled = False
        picEdit.BorderStyle = BorderStyles.NoBorder
        picEdit.Properties.SizeMode = PictureSizeMode.Squeeze
        picEdit.Properties.UseDisabledStatePainter = False
        Return picEdit
    End Function
End Class

Run Demo: Preview SVG Files

Customize Context Menu

Handle the following events to customize context menus (add new commands, hide/disable commands, etc.) in the WinForms File Explorer Assistant component:

  • ContextMenuShowing
  • BeforeExecuteItemCommand

csharp
assistant.Attach(grid, x => {
    x.CurrentPath = initialPath;
    string customCommandName = "custom";
    x.ContextMenuShowing += (s, e) => {
        e.MenuItems.AddCommand("Custom command", customCommandName);
    };

    x.BeforeExecuteItemCommand += (s, e) => {
        if(e.CommandName == customCommandName) {
            XtraMessageBox.Show("Custom command executed");
            e.Cancel = true;
        }
    };
});
vb
assistant.Attach(grid, Sub(x)
    x.CurrentPath = initialPath
    Dim customCommandName As String = "custom"
    AddHandler x.ContextMenuShowing, Sub(s, e)
        e.MenuItems.AddCommand("Custom command", customCommandName)
    End Sub
    AddHandler x.BeforeExecuteItemCommand, Sub(s, e)
        If e.CommandName = customCommandName Then
            XtraMessageBox.Show("Custom command executed")
            e.Cancel = True
        End If
    End Sub
End Sub)

Run Demo: Customize Context Menu