Comment configurer un OpenFileDialog pour sélectionner des dossiers?

dans VS .NET, lorsque vous sélectionnez un dossier pour un projet, une boîte de dialogue qui ressemble à un OpenFileDialog ou SaveFileDialog est affichée, mais est configurée pour accepter uniquement les dossiers. Depuis que j'ai vu ça, j'ai toujours voulu savoir comment faire. Je suis au courant du FolderBrowserDialog, mais je n'ai jamais vraiment aimé ce dialogue. Il commence trop petit et ne me laisse pas profiter de pouvoir taper un chemin.

je suis presque sûr qu'il n'y a plus de moyen de faire ça de .NET, mais je suis tout aussi curieux de savoir comment vous le faites à partir de code non géré. A moins de réimplémenter complètement la boîte de dialogue à partir de zéro, comment modifier la boîte de dialogue pour avoir ce comportement?

je tiens aussi à réaffirmer que je suis au courant du FolderBrowserDialog mais parfois je n'aime pas l'utiliser, en plus d'être vraiment curieux de savoir comment configurer un dialogue de cette manière. Me dire d'utiliser simplement le FolderBrowserDialog m'aide à maintenir une expérience D'assurance-chômage cohérente mais ça ne répond pas à ma curiosité donc ça ne comptera pas comme une réponse.

ce n'est pas une chose spécifique à Vista non plus; j'ai vu ce dialogue depuis VS .NET 2003, il est donc faisable dans Win2k et WinXP. Il s'agit moins d'une question "je veux savoir la bonne façon de faire" que d'une question "j'ai été curieux depuis que j'ai voulu le faire dans VS 2003". Je comprends que le dialogue de fichier de Vista a une option pour faire cela, mais il a fonctionné dans XP donc je sais qu'ils ont fait quelque chose pour le faire fonctionner. Les réponses spécifiques à Vista ne sont pas des réponses, parce que Vista n'existe pas dans le contexte de la question.

mise à jour: j'accepte la réponse de Scott Wisniewski parce qu'il est livré avec un échantillon de travail, mais je pense que Serge mérite le crédit pour pointer du doigt la personnalisation de dialogue (qui est certes méchant de .NET mais il ne travail) et Mark Ransom pour comprendre que MS probablement roulé un boîte de dialogue pour cette tâche.

237
demandé sur Steve 2008-08-27 23:54:16

17 réponses

j'ai un dialogue que j'ai écrit appelé un dialogue OpenFileOrFolder qui vous permet d'ouvrir un dossier ou un fichier.

si vous définissez sa valeur AcceptFiles à false, alors il fonctionne en mode accept folder.

vous pouvez télécharger la source de GitHub ici

53
répondu Scott Wisniewski 2017-03-28 01:39:04

il y a le Pack de code API Windows. Il y a beaucoup de choses liées à shell, y compris la classe CommonOpenFileDialog (dans l'espace de noms Microsoft.WindowsAPICodePack.Dialogs ). C'est la solution parfaite - le dialogue ouvert habituel avec seulement les dossiers affichés.

voici un exemple d'utilisation:

CommonOpenFileDialog cofd = new CommonOpenFileDialog();
cofd.IsFolderPicker = true;
cofd.ShowDialog();

malheureusement Microsoft ne Livre plus ce paquet, mais plusieurs personnes ont officieusement téléchargé des binaires à NuGet. Un exemple peut être trouvé ici . Ce paquet est spécifique à l'interpréteur de commandes. Si vous en avez besoin, le même utilisateur a plusieurs autres paquets qui offrent plus de fonctionnalités présentes dans le paquet original.

46
répondu Ken Wayne VanderLinde 2016-05-20 10:43:46

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 également rechercher des ordinateurs ou des imprimantes. Fonctionne comme le FBD intégré, mais ... mieux.

(EDIT: je devrais avoir souligné que ce dialogue peut être configurée pour sélectionner des fichiers ou des dossiers. )

code source complet (un module C court). Gratuit. MS-Licence Publique.

Code d'utilisation:

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;
}
46
répondu Cheeso 2018-03-06 23:55:26

Le Ookii.Le paquet Dialogs contient un wrapper managé autour du nouveau navigateur de dossier (Style Vista). Il se dégrade également avec élégance sur les systèmes d'exploitation plus anciens.

33
répondu Christian Klauser 2018-10-04 03:26:58

il est préférable d'utiliser le FolderBrowserDialog pour cela.

using (FolderBrowserDialog dlg = new FolderBrowserDialog())
{
    dlg.Description = "Select a folder";
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        MessageBox.Show("You selected: " + dlg.SelectedPath);
    }
}
28
répondu Ryan Farley 2008-08-27 19:59:17

après des heures de recherche j'ai trouvé cette réponse par leetNightShade à une solution de travail .

je crois qu'il y a trois choses qui rendent cette solution bien meilleure que toutes les autres.

  1. il est simple à utiliser. Il vous suffit d'inclure deux fichiers (qui peuvent être combinés en un seul de toute façon) dans votre projet.
  2. Il revient à la norme FolderBrowserDialog lorsqu'il est utilisé sur XP ou des systèmes plus anciens.
  3. l'auteur accorde la permission d'utiliser le code à toute fin que vous jugez appropriée.

    il n'y a pas de licence en tant que telle que vous êtes libre de prendre et de faire avec le code ce que vous voulez.

Téléchargez le code ici .

23
répondu Alex Essilfie 2017-05-23 12:18:08

OK, laissez-moi essayer de connecter le premier point ;-) Jouer un peu avec Spy++ ou Winspector montre que la boîte de texte du dossier dans L'emplacement du projet VS est une personnalisation de la boîte de dialogue standard. Ce n'est pas le même champ que la boîte de dialogue textbox du nom de fichier dans un fichier standard tel que celui du bloc-notes.

à partir de là, je me figure, VS cache le nom de fichier et les boîtes de texte filetype/comboboxes et utilise un modèle de dialogue personnalisé pour ajouter sa propre partie dans le bas de la boîte de dialogue.

EDIT: voici un exemple d'une telle personnalisation et comment le faire (dans Win32. non publié):

m_ofn est la structure OPENFILENAME qui sous-tend la boîte de dialogue Fichier. Ajouter ces 2 lignes:

  m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEDIALOG_IMPORTXLIFF);
  m_ofn.Flags |= OFN_ENABLETEMPLATE;

où IDD_FILEDIALOG_IMPORTXLIFF est un modèle de dialogue personnalisé qui sera ajouté en bas de la boîte de dialogue. Voir la partie en rouge ci-dessous. alt texte http://apptranslator.com/_so/customizedfiledialog.png

Dans ce cas, la mesure n'est qu'une étiquette + un lien hypertexte, mais il pourrait être n'importe quel dialogue. Il pourrait contenir un bouton OK qui nous permettrait de valider la sélection dossier seulement.

mais comment se débarrasser de certains contrôles dans la partie standard du dialogue, Je ne sais pas.

plus de détails dans cet article de MSDN .

17
répondu Serge Wautier 2009-02-03 22:05:32

Exact Audio Copy fonctionne de cette façon sur Windows XP. La boîte de dialogue Ouvrir le fichier standard est affichée, mais le champ filename contient le texte "Filename will be ignored".

je suppose ici, mais je soupçonne que la chaîne est injectée dans la boîte bascule éditer le contrôle chaque fois qu'un changement significatif est fait à la boîte de dialogue. Tant que le champ n'est pas vide, et que les indicateurs de dialogue sont définis pour ne pas vérifier l'existence du fichier, le dialogue peut être fermé normalement.

Edit: c'est beaucoup plus facile que je ne le pensais. Voici le code en C++/MFC, vous pouvez le traduire dans l'environnement de votre choix.

CFileDialog dlg(true, NULL, "Filename will be ignored", OFN_HIDEREADONLY | OFN_NOVALIDATE | OFN_PATHMUSTEXIST | OFN_READONLY, NULL, this);
dlg.DoModal();

Edit 2: Ce doit être la traduction en C#, mais je ne suis pas à l'aise en C# afin de ne pas me tirer dessus si ça ne fonctionne pas.

OpenFileDialog openFileDialog1 = new OpenFileDialog();

openFileDialog1.FileName = "Filename will be ignored";
openFileDialog1.CheckPathExists = true;
openFileDialog1.ShowReadOnly = false;
openFileDialog1.ReadOnlyChecked = true;
openFileDialog1.CheckFileExists = false;
openFileDialog1.ValidateNames = false;

if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
    // openFileDialog1.FileName should contain the folder and a dummy filename
}

Edit 3: Enfin regardé le dialogue en question, en Visual Studio 2005 (je n'y avais pas accès plus tôt). ce n'est pas le dialogue Ouvrir fichier standard! si vous examinez les fenêtres dans Spy++ et les comparez à un fichier standard ouvrir, vous verrez que la structure et les noms de classe ne correspondent pas. Lorsque vous regardez de près, vous pouvez également repérer certaines différences entre le contenu des dialogues. Ma conclusion est que Microsoft a complètement remplacé le dialogue standard dans Visual Studio pour lui donner cette capacité. Ma solution ou quelque chose le même sera aussi proche que vous pouvez obtenir, à moins que vous êtes prêt à coder votre propre à partir de zéro.

17
répondu Mark Ransom 2009-02-05 15:57:19

vous pouvez sous-classe le dialogue fichier et accéder à toutes ses commandes. Chacun a un identifiant qui peut être utilisé pour obtenir sa poignée de fenêtre. Vous pouvez alors les afficher et les cacher, leur envoyer des messages sur les changements de sélection, etc. etc. Tout dépend de l'effort que vous voulez faire.

nous avons fait le nôtre en utilisant le soutien de classe WTL et personnalisé la boîte de dialogue de dossier pour inclure une barre de lieux personnalisée et des vues com plug-in.

MSDN cet article de Codeprojet inclut un exemple , et cet article de Codeprojet fournit un exemple .NET .

10
répondu Jeff Yates 2009-02-03 22:04:16

vous pouvez utiliser le code comme ceci

  • le filtre est masquer les fichiers

  • le nom du fichier est cacher le premier texte

avancé cacher de la zone de texte pour le nom de fichier que vous devez regarder OpenFileDialogEx

le code:

{
    openFileDialog2.FileName = "\r";
    openFileDialog1.Filter = "folders|*.neverseenthisfile";
    openFileDialog1.CheckFileExists = false;
    openFileDialog1.CheckPathExists = false;
}
9
répondu Avram 2016-04-10 09:55:41

je suppose que vous êtes sur Vista en utilisant VS2008? Dans ce cas, je pense que l'option FOS_PICKFOLDERS est utilisée pour appeler la boîte de dialogue IFileDialog . Je crains que dans le code .NET cela impliquerait beaucoup de gnarly P / invoquer le code interop pour se mettre au travail.

5
répondu Duncan Smart 2008-08-28 01:32:43

Première Solution

j'ai développé ceci comme une version nettoyée de . net Win 7-style dossier sélectionner dialogue par Bill Seddon de lyquidity.com (Je n'ai pas d'affiliation). (J'ai appris son code de une autre réponse sur cette page ). J'ai écrit le mien parce que sa solution nécessite une classe de réflexion supplémentaire qui n'est pas nécessaire à cette fin ciblée, utilise contrôle de flux basé sur l'exception, ne cache pas les résultats de ses appels de réflexion. Notez que la classe statique imbriquée VistaDialog est telle que ses variables de réflexion statique n'essaient pas d'être peuplées si la méthode Show n'est jamais appelée. Il retourne à la boîte de dialogue pré-Vista si ce n'est pas dans une version Windows assez haute. Devrait fonctionner dans Windows 7, 8, 9, 10 et plus (théoriquement).

using System;
using System.Reflection;
using System.Windows.Forms;

namespace ErikE.Shuriken {
    /// <summary>
    /// Present the Windows Vista-style open file dialog to select a folder. Fall back for older Windows Versions
    /// </summary>
    public class FolderSelectDialog {
        private string _initialDirectory;
        private string _title;
        private string _fileName = "";

        public string InitialDirectory {
            get { return string.IsNullOrEmpty(_initialDirectory) ? Environment.CurrentDirectory : _initialDirectory; }
            set { _initialDirectory = value; }
        }
        public string Title {
            get { return _title ?? "Select a folder"; }
            set { _title = value; }
        }
        public string FileName { get { return _fileName; } }

        public bool Show() { return Show(IntPtr.Zero); }

        /// <param name="hWndOwner">Handle of the control or window to be the parent of the file dialog</param>
        /// <returns>true if the user clicks OK</returns>
        public bool Show(IntPtr hWndOwner) {
            var result = Environment.OSVersion.Version.Major >= 6
                ? VistaDialog.Show(hWndOwner, InitialDirectory, Title)
                : ShowXpDialog(hWndOwner, InitialDirectory, Title);
            _fileName = result.FileName;
            return result.Result;
        }

        private struct ShowDialogResult {
            public bool Result { get; set; }
            public string FileName { get; set; }
        }

        private static ShowDialogResult ShowXpDialog(IntPtr ownerHandle, string initialDirectory, string title) {
            var folderBrowserDialog = new FolderBrowserDialog {
                Description = title,
                SelectedPath = initialDirectory,
                ShowNewFolderButton = false
            };
            var dialogResult = new ShowDialogResult();
            if (folderBrowserDialog.ShowDialog(new WindowWrapper(ownerHandle)) == DialogResult.OK) {
                dialogResult.Result = true;
                dialogResult.FileName = folderBrowserDialog.SelectedPath;
            }
            return dialogResult;
        }

        private static class VistaDialog {
            private const string c_foldersFilter = "Folders|\n";

            private const BindingFlags c_flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
            private readonly static Assembly s_windowsFormsAssembly = typeof(FileDialog).Assembly;
            private readonly static Type s_iFileDialogType = s_windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog");
            private readonly static MethodInfo s_createVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("CreateVistaDialog", c_flags);
            private readonly static MethodInfo s_onBeforeVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("OnBeforeVistaDialog", c_flags);
            private readonly static MethodInfo s_getOptionsMethodInfo = typeof(FileDialog).GetMethod("GetOptions", c_flags);
            private readonly static MethodInfo s_setOptionsMethodInfo = s_iFileDialogType.GetMethod("SetOptions", c_flags);
            private readonly static uint s_fosPickFoldersBitFlag = (uint) s_windowsFormsAssembly
                .GetType("System.Windows.Forms.FileDialogNative+FOS")
                .GetField("FOS_PICKFOLDERS")
                .GetValue(null);
            private readonly static ConstructorInfo s_vistaDialogEventsConstructorInfo = s_windowsFormsAssembly
                .GetType("System.Windows.Forms.FileDialog+VistaDialogEvents")
                .GetConstructor(c_flags, null, new[] { typeof(FileDialog) }, null);
            private readonly static MethodInfo s_adviseMethodInfo = s_iFileDialogType.GetMethod("Advise");
            private readonly static MethodInfo s_unAdviseMethodInfo = s_iFileDialogType.GetMethod("Unadvise");
            private readonly static MethodInfo s_showMethodInfo = s_iFileDialogType.GetMethod("Show");

            public static ShowDialogResult Show(IntPtr ownerHandle, string initialDirectory, string title) {
                var openFileDialog = new OpenFileDialog {
                    AddExtension = false,
                    CheckFileExists = false,
                    DereferenceLinks = true,
                    Filter = c_foldersFilter,
                    InitialDirectory = initialDirectory,
                    Multiselect = false,
                    Title = title
                };

                var iFileDialog = s_createVistaDialogMethodInfo.Invoke(openFileDialog, new object[] { });
                s_onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, new[] { iFileDialog });
                s_setOptionsMethodInfo.Invoke(iFileDialog, new object[] { (uint) s_getOptionsMethodInfo.Invoke(openFileDialog, new object[] { }) | s_fosPickFoldersBitFlag });
                var adviseParametersWithOutputConnectionToken = new[] { s_vistaDialogEventsConstructorInfo.Invoke(new object[] { openFileDialog }), 0U };
                s_adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken);

                try {
                    int retVal = (int) s_showMethodInfo.Invoke(iFileDialog, new object[] { ownerHandle });
                    return new ShowDialogResult {
                        Result = retVal == 0,
                        FileName = openFileDialog.FileName
                    };
                }
                finally {
                    s_unAdviseMethodInfo.Invoke(iFileDialog, new[] { adviseParametersWithOutputConnectionToken[1] });
                }
            }
        }

        // Wrap an IWin32Window around an IntPtr
        private class WindowWrapper : IWin32Window {
            private readonly IntPtr _handle;
            public WindowWrapper(IntPtr handle) { _handle = handle; }
            public IntPtr Handle { get { return _handle; } }
        }
    }
}

il est utilisé comme ainsi Sous la forme de Windows:

var dialog = new FolderSelectDialog {
    InitialDirectory = musicFolderTextBox.Text,
    Title = "Select a folder to import music from"
};
if (dialog.Show(Handle)) {
    musicFolderTextBox.Text = dialog.FileName;
}

vous pouvez bien sûr jouer avec ses options et les propriétés qu'il expose. Par exemple, il permet le multi-sélect dans le dialogue Vista-style.

Deuxième Solution

Simon Mourier a donné une réponse qui montre comment faire le même travail en utilisant interop contre L'API Windows directement, bien que sa version devrait être complété pour utiliser la boîte de dialogue de style plus ancien si dans une version plus ancienne de Windows. Malheureusement, je n'avais pas encore trouvé son poste quand j'ai trouvé ma solution. Nomme ton poison!

2
répondu ErikE 2017-10-16 17:31:11

Essayez de celui de la Codeproject (crédit à Nitron):

je pense que c'est le même dialogue dont vous parlez - peut-être que cela aiderait si vous ajoutez une capture d'écran?

bool GetFolder(std::string& folderpath, const char* szCaption=NULL, HWND hOwner=NULL)
{
    bool retVal = false;

    // The BROWSEINFO struct tells the shell how it should display the dialog.
    BROWSEINFO bi;
    memset(&bi, 0, sizeof(bi));

    bi.ulFlags   = BIF_USENEWUI;
    bi.hwndOwner = hOwner;
    bi.lpszTitle = szCaption;

    // must call this if using BIF_USENEWUI
    ::OleInitialize(NULL);

    // Show the dialog and get the itemIDList for the selected folder.
    LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi);

    if(pIDL != NULL)
    {
        // Create a buffer to store the path, then get the path.
        char buffer[_MAX_PATH] = {'"151900920"'};
        if(::SHGetPathFromIDList(pIDL, buffer) != 0)
        {
            // Set the string value.
            folderpath = buffer;
            retVal = true;
        }       

        // free the item id list
        CoTaskMemFree(pIDL);
    }

    ::OleUninitialize();

    return retVal;
}
1
répondu demoncodemonkey 2009-02-03 08:39:09

sur Vista vous pouvez utiliser IFileDialog avec l'option FOS_PICKFOLDERS. Cela provoquera l'affichage de la fenêtre de type OpenFileDialog où vous pouvez sélectionner les dossiers:

var frm = (IFileDialog)(new FileOpenDialogRCW());
uint options;
frm.GetOptions(out options);
options |= FOS_PICKFOLDERS;
frm.SetOptions(options);

if (frm.Show(owner.Handle) == S_OK) {
    IShellItem shellItem;
    frm.GetResult(out shellItem);
    IntPtr pszString;
    shellItem.GetDisplayName(SIGDN_FILESYSPATH, out pszString);
    this.Folder = Marshal.PtrToStringAuto(pszString);
}

pour les fenêtres plus anciennes, vous pouvez toujours avoir recours à trick pour sélectionner un fichier dans le dossier.

exemple de travail qui fonctionne sur .net Framework 2.0 et plus tard peut être trouvé ici .

1
répondu Josip Medved 2012-01-04 01:18:33

vous pouvez utiliser le code comme ceci

Le filtre est une chaîne vide. Le nom du fichier est unnom mais pas blanc

        openFileDialog.FileName = "AnyFile";
        openFileDialog.Filter = string.Empty;
        openFileDialog.CheckFileExists = false;
        openFileDialog.CheckPathExists = false;
1
répondu lantran 2012-03-19 03:02:24

je sais que la question était sur la configuration de OpenFileDialog mais en voyant que Google m'a amené ici, je peux aussi bien faire remarquer que si vous cherchez seulement des dossiers, vous devriez utiliser un FolderBrowserDialog à la place comme répondu par une autre question SO ci-dessous

comment spécifier le chemin en utilisant la boîte de dialogue Ouvrir le fichier vb.net Je ne sais pas.

0
répondu AltF4_ 2017-10-12 15:04:35

la bibliothèque Dialogs Ookii pour WPF a une classe qui fournit une mise en œuvre d'un dialogue de navigateur de dossier pour WPF.

https://github.com/caioproiete/ookii-dialogs-wpf

enter image description here

il y a aussi une version qui fonctionne avec Windows Forms .

0
répondu Caio Proiete 2018-10-04 03:31:48