Sélectionnez un fichier ou un dossier dans la même boîte de dialogue dans .NET
-
06-07-2019 - |
Question
Existe-t-il un "facile" " moyen de sélectionner un fichier OU un dossier de la même boîte de dialogue?
Dans de nombreuses applications que je crée, j'autorise les fichiers ou les dossiers en entrée. Jusqu'à présent, je finissais toujours par créer un commutateur permettant de basculer entre les boîtes de dialogue de sélection de fichiers ou de dossiers ou de n'utiliser que la fonctionnalité glisser-déposer.
Étant donné que cela semble si fondamental, j’imagine que cela a déjà été créé, mais googler ne donne pas beaucoup d’informations. Il me semble donc que je devrais commencer à partir de zéro et créer un dialogue de sélection personnalisé, mais je préfère ne pas poser de problèmes en réinventant la roue pour une tâche aussi triviale.
Quelqu'un a des conseils ou des solutions existantes?
Pour que l'interface utilisateur reste cohérente, il serait utile de pouvoir étendre OpenFileDialog (ou FolderBrowserDialog).
La solution
Techniquement, c'est possible. La boîte de dialogue shell utilisée par FolderBrowseDialog peut renvoyer des fichiers et des dossiers. Malheureusement, cette fonctionnalité n'est pas exposée dans .NET. Même la réflexion ne peut déclencher l'indicateur d'option requis.
Pour que cela fonctionne, vous devez P / Invoke SHBrowseForFolder () avec le drapeau BIF_BROWSEINCLUDEFILES activé dans BROWSEINFO.ulFlags (valeur = 0x4000). Le P / Invoke est graveleux, il est préférable de copier et coller le code de une autre source ou la classe FolderBrowseDialog elle-même avec l'aide de Reflector.
Autres conseils
Sur la base des conseils ci-dessus, j'ai trouvé un code fonctionnel qui utilise la boîte de dialogue standard du navigateur de dossiers à l'emplacement suivant: http://topic.csdn.net/t/20020703/05/845468.html
Classe de la boîte de dialogue étendue du navigateur de dossiers
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
Le code pour implémenter la boîte de dialogue étendue
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
Vous pouvez utiliser OpenFileDialog standard pour sélectionner un dossier. Voici un article de CodeProject qui montre une façon de le faire ( http: // www. codeproject.com/KB/dialog/OpenFileOrFolderDialog.aspx ).
Cela a été fait. Vous pouvez utiliser FolderBrowserDialogEx - un dérivé réutilisable du FolderBrowserDialog intégré. Celui-ci vous permet de taper un chemin, même un chemin UNC. Vous pouvez rechercher des dossiers ou des fichiers + dossiers. Vous pouvez rechercher des ordinateurs ou des imprimantes avec. Basé sur le FBD intégré, mais ... meilleur. Plus flexible. Si vous cliquez sur un dossier dans l'interface graphique, le chemin d'accès apparaît dans la zone de texte. Si vous entrez un chemin, le dossier est activé. La boîte de dialogue intégrée manque de nombreuses options.
Code source complet. Libre. Licence MS-Public.
Code pour l'utiliser:
var dlg1 = new Ionic.Utils.FolderBrowserDialogEx();
dlg1.Description = "Select a folder to extract to:";
dlg1.ShowNewFolderButton = true;
dlg1.ShowEditBox = true;
//dlg1.NewStyle = false;
dlg1.SelectedPath = txtExtractDirectory.Text;
dlg1.ShowFullPathInEditBox = true;
dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer;
// Show the FolderBrowserDialog.
DialogResult result = dlg1.ShowDialog();
if (result == DialogResult.OK)
{
txtExtractDirectory.Text = dlg1.SelectedPath;
}
Les boîtes de dialogue de fichiers .NET proviennent de CommonDialog :
Les classes héritées sont requises pour implémenter RunDialog en appelant ShowDialog pour créer un commun spécifique boite de dialogue. Les classes héritées peuvent remplacer HookProc pour implémenter crochet de boîte de dialogue spécifique fonctionnalité.
Toutes les boîtes de dialogue intégrées utilisent les API du shell correspondant à leur action, PrintDialog, OpenFileDialog, SaveFileDialog, etc ...
Vous devrez probablement créer manuellement cette fonctionnalité.
http://www.pinvoke.net/default.aspx/shell32.shbrowseforfolder
voici un lien de gerat si vous modifiez cet exemple
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_SHAREABLE;
pour
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_SHAREABLE | BIF_BROWSEINCLUDEFILES;
vous obtiendrez ce que vous voulez
Si vous souhaitez afficher uniquement des types de fichiers spécifiques, procédez comme suit: article (avec le code source en C #) peut vous aider:
Il explique également les autres options disponibles pour la & personnalisation " la boîte de dialogue FolderBrowser,
cela vous permettra de sélectionner des dossiers en utilisant OpenFileDialog
openFileDialog1.CheckFileExists = false;
openFileDialog1.ValidateNames = false;
Les boîtes de dialogue Ookii implémentent une boîte de dialogue de navigation dans les dossiers fichiers ou dossiers en entrée et est disponible pour Windows Forms et WPF.
Ookii.Dialogs.Wpf
Ookii.Dialogs.WinForms