33 votes

Sélectionnez un fichier ou un dossier dans la même boîte de dialogue en .NET.

Existe-t-il un moyen "simple" de sélectionner un fichier OU un dossier dans la même boîte de dialogue ?

Dans de nombreuses applications que je crée, j'autorise la saisie de fichiers ou de dossiers. Jusqu'à présent, j'ai toujours fini par créer un commutateur permettant de basculer entre les boîtes de dialogue de sélection de fichiers ou de dossiers, ou par m'en tenir à la seule fonctionnalité de glisser-déposer.

Puisque cela semble si élémentaire, j'imagine que cela a déjà été créé auparavant, mais une recherche sur Google ne donne pas beaucoup d'informations. Il semblerait donc que je doive repartir de zéro et créer un dialogue de sélection personnalisé, mais je préfère ne pas introduire de problèmes en réinventant la roue pour une tâche aussi triviale.

Quelqu'un a-t-il des conseils ou des solutions existantes ?

Pour que l'interface utilisateur reste cohérente, il serait bon qu'il soit possible d'étendre le OpenFileDialog (ou le FolderBrowserDialog).

5 votes

Cette question est très similaire à celle que j'ai posée. Vous pouvez y trouver une référence intéressante. stackoverflow.com/questions/100264/

0 votes

Consultez le Dialogues d'Ookii Les bibliothèques qui ont des implémentations d'un dialogue de navigateur de dossiers pour Windows Forms et WPF respectivement...

13voto

Hans Passant Points 475940

Techniquement, c'est possible. Le dialogue shell utilisé par FolderBrowseDialog a la capacité de retourner à la fois les fichiers et les dossiers. Malheureusement, cette capacité n'est pas exposée dans .NET. Même la réflexion ne permet pas d'activer le drapeau d'option requis.

Pour que cela fonctionne, vous devez P/Invoke SHBrowseForFolder() avec l'indicateur BIF_BROWSEINCLUDEFILES activé dans BROWSEINFO.ulFlags (valeur = 0x4000). Le P/Invoke est granuleux, il est préférable de copier et coller le code à partir de une autre source ou la classe FolderBrowseDialog elle-même avec l'aide de Reflector.

2 votes

Merci, les BIF_BROWSEINCLUDEFILES ont fait l'affaire. Voir la réponse ci-dessous pour un exemple de code.

7voto

barry Points 476

En me basant sur les conseils ci-dessus, j'ai trouvé un code fonctionnel qui utilise la boîte de dialogue standard Folder Browser à l'endroit suivant : http://topic.csdn.net/t/20020703/05/845468.html

La classe pour 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 le dialogue étendu

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

1 votes

J'ai converti cette classe en C# pour toute personne intéressée ( pastebin.com/33X93vKt ).

5voto

Cheeso Points 87022

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. Basé sur le FBD intégré, mais ... meilleur. Plus flexible. Si vous cliquez sur un dossier dans l'interface graphique, le chemin apparaît dans la zone de texte. Si vous entrez un chemin, le dossier est activé. Beaucoup d'options qui manquent à la boîte de dialogue intégrée.

Code source complet. Gratuit. Licence MS-Public.

FolderBrowserDialogEx

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;
     }

6 votes

Pour épargner à d'autres personnes ce problème à l'avenir, j'ai utilisé cette boîte de dialogue et elle ne permet pas les sélections multiples. Et pour qu'elle puisse sélectionner des fichiers, votre réponse devrait mentionner le réglage de dlg1.ShowBothFilesAndFolders = true ;

5voto

stankovski Points 1294

Vous pouvez utiliser l'OpenFileDialog standard pour sélectionner un dossier. Voici un article de CodeProject qui démontre une façon de le faire ( http://www.codeproject.com/KB/dialog/OpenFileOrFolderDialog.aspx ).

1 votes

Merci ! J'ai fait un essai, mais je n'ai pas réussi à le faire fonctionner. La boîte de dialogue d'ouverture de fichier ne pouvait qu'ouvrir des fichiers. C'est peut-être lié au système d'exploitation (j'utilise Windows 7). Ce serait vraiment bien si nous pouvions utiliser la boîte de dialogue d'ouverture de fichier sans avoir à créer un contrôle personnalisé à partir de zéro. Les solutions précédentes utilisant des dialogues de sélection de dossier "étendus" fonctionnent mais l'interface utilisateur qui en résulte semble dépassée.

1 votes

J'ai trouvé le problème avec Windows 7. En plus de ValidateNames, les 2 drapeaux suivants doivent être définis : dialog.CheckFileExists = false ; dialog.CheckPathExists = true ;

0 votes

@stankovski Pouvez-vous me donner un exemple de code sur la façon dont vous l'avez fait ? Je n'arrive pas à comprendre. J'obtiens des erreurs et je ne sais pas comment ou où utiliser le code. Dois-je créer une nouvelle classe ou l'utiliser dans le formulaire principal ? La partie de réinitialisation donne une erreur disant qu'elle ne peut pas la remplacer. Je suis novice en C#. Merci d'avance.

1voto

Mitch Wheat Points 169614

A ma connaissance, il n'y a rien dans le cadre .NET qui permette de faire cela.

Les boîtes de dialogue de fichiers .NET dérivent de CommonDialog :

Les classes héritées doivent d'implémenter RunDialog en invoquant ShowDialog pour créer une boîte de boîte de dialogue commune. Les classes héritées peuvent surcharger HookProc pour implémenter crochet de boîte de dialogue spécifique de la boîte de dialogue.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X