Is there an "easy" way to select either a file OR a folder from the same dialog?
In many apps I create I allow for both files or folders as input. Until now i always end up creating a switch to toggle between file or folder selection dialogs or stick with drag-and-drop functionality only.
Since this seems such a basic thing i would imagine this has been created before, but googling does not result in much information. So it looks like i would need to start from scratch and create a custom selection Dialog, but I rather not introduce any problems by reinventing the wheel for such a trivial task.
Anybody any tips or existing solutions?
To keep the UI consistent it would be nice if it is possible to extend the OpenFileDialog (or the FolderBrowserDialog).
Technically, it is possible. The shell dialog used by FolderBrowseDialog has the ability to return both files and folders. Unfortunately, that capability isn't exposed in .NET. Not even reflection can poke the required option flag.
To make it work, you'd have to P/Invoke SHBrowseForFolder() with the BIF_BROWSEINCLUDEFILES flag turned on in BROWSEINFO.ulFlags (value = 0x4000). The P/Invoke is gritty, it is best to copy and paste the code from another source or the FolderBrowseDialog class itself with Reflector's help.
Based on the above tips I found some working code that uses the standard Folder Browser dialog at the following location: http://topic.csdn.net/t/20020703/05/845468.html
The Class for the extended Folder Browser Dialog
Imports System Imports System.Text Imports System.Windows.Forms Imports System.Runtime.InteropServices Public Class DirectoryDialog Public Structure BROWSEINFO Public hWndOwner As IntPtr Public pIDLRoot As Integer Public pszDisplayName As String Public lpszTitle As String Public ulFlags As Integer Public lpfnCallback As Integer Public lParam As Integer Public iImage As Integer End Structure Const MAX_PATH As Integer = 260 Public Enum BrowseForTypes As Integer Computers = 4096 Directories = 1 FilesAndDirectories = 16384 FileSystemAncestors = 8 End Enum Declare Function CoTaskMemFree Lib "ole32" Alias "CoTaskMemFree" (ByVal hMem As IntPtr) As Integer Declare Function lstrcat Lib "kernel32" Alias "lstrcat" (ByVal lpString1 As String, ByVal lpString2 As String) As IntPtr Declare Function SHBrowseForFolder Lib "shell32" Alias "SHBrowseForFolder" (ByRef lpbi As BROWSEINFO) As IntPtr Declare Function SHGetPathFromIDList Lib "shell32" Alias "SHGetPathFromIDList" (ByVal pidList As IntPtr, ByVal lpBuffer As StringBuilder) As Integer Protected Function RunDialog(ByVal hWndOwner As IntPtr) As Boolean Dim udtBI As BROWSEINFO = New BROWSEINFO() Dim lpIDList As IntPtr Dim hTitle As GCHandle = GCHandle.Alloc(Title, GCHandleType.Pinned) udtBI.hWndOwner = hWndOwner udtBI.lpszTitle = Title udtBI.ulFlags = BrowseFor Dim buffer As StringBuilder = New StringBuilder(MAX_PATH) buffer.Length = MAX_PATH udtBI.pszDisplayName = buffer.ToString() lpIDList = SHBrowseForFolder(udtBI) hTitle.Free() If lpIDList.ToInt64() <> 0 Then If BrowseFor = BrowseForTypes.Computers Then m_Selected = udtBI.pszDisplayName.Trim() Else Dim path As StringBuilder = New StringBuilder(MAX_PATH) SHGetPathFromIDList(lpIDList, path) m_Selected = path.ToString() End If CoTaskMemFree(lpIDList) Else Return False End If Return True End Function Public Function ShowDialog() As DialogResult Return ShowDialog(Nothing) End Function Public Function ShowDialog(ByVal owner As IWin32Window) As DialogResult Dim handle As IntPtr If Not owner Is Nothing Then handle = owner.Handle Else handle = IntPtr.Zero End If If RunDialog(handle) Then Return DialogResult.OK Else Return DialogResult.Cancel End If End Function Public Property Title() As String Get Return m_Title End Get Set(ByVal Value As String) If Value Is DBNull.Value Then Throw New ArgumentNullException() End If m_Title = Value End Set End Property Public ReadOnly Property Selected() As String Get Return m_Selected End Get End Property Public Property BrowseFor() As BrowseForTypes Get Return m_BrowseFor End Get Set(ByVal Value As BrowseForTypes) m_BrowseFor = Value End Set End Property Private m_BrowseFor As BrowseForTypes = BrowseForTypes.Directories Private m_Title As String = "" Private m_Selected As String = "" Public Sub New() End Sub End Class
The code to implement the extended dialog
Sub Button1Click(ByVal sender As Object, ByVal e As EventArgs) Dim frmd As DirectoryDialog = New DirectoryDialog() ' frmd.BrowseFor = DirectoryDialog.BrowseForTypes.Directories ' frmd.BrowseFor = DirectoryDialog.BrowseForTypes.Computers frmd.BrowseFor = DirectoryDialog.BrowseForTypes.FilesAndDirectories frmd.Title = "Select a file or a folder" If frmd.ShowDialog(Me) = DialogResult.OK Then MsgBox(frmd.Selected) End If End Sub