364 votes

Comment utiliser OpenFileDialog pour sélectionner un dossier ?

Mode d'emploi OpenFileDialog pour sélectionner les dossiers ?

J'avais l'intention d'utiliser le projet suivant : https://github.com/scottwis/OpenFileOrFolderDialog

Cependant, j'ai été confronté à un problème. Il utilise le GetOpenFileName et OPENFILENAME structure. Et OPENFILENAME a le membre nommé templateID . C'est l'identifiant du modèle de dialogue. Et le projet contient le res1.rc et l'init de la boîte de dialogue modèle, également. Mais je n'ai pas réussi à trouver comment joindre ce fichier à mon projet C#.

Y a-t-il une meilleure façon d'utiliser un OpenFileDialog pour sélectionner les dossiers ?

0 votes

Si vous ouvrez le fichier du projet avec l'éditeur, vous remarquerez quelques propriétés supplémentaires en bas : <VCIncludePath ...>, <Win32Resource ...> et <Target Name="BeforeBuild"...>. Vous verrez qu'il exécute rc.exe pour compiler le fichier ressource res1.rc (assurez-vous de copier également le fichier "resource.h" dans votre projet). Assurez-vous que vous avez installé VisualC et que VCIncludePath pointe vers un emplacement approprié (celui de github pointe vers la version VC9.0, et vous devrez peut-être le changer). Après avoir compilé le fichier .rc, le fichier .res résultant est ajouté comme ressource pour votre exécutable avec la directive Win32Resource.

3 votes

Il existe une solution bricolée utilisant OpenFileDialog où ValidateNames y CheckFileExists sont tous deux mis à faux et FileName reçoit une valeur fictive pour indiquer qu'un répertoire est sélectionné. Je dis "hack" parce que cela prête à confusion pour les utilisateurs sur la façon de sélectionner un répertoire. Voir Sélectionnez un fichier ou un dossier dans la même boîte de dialogue

0 votes

8voto

Ben Keene Points 381

Voici une autre solution, qui dispose de toutes les sources dans un fichier ZIP simple et unique.

Il présente le OpenFileDialog avec des drapeaux Windows supplémentaires qui le font fonctionner comme le dialogue de sélection de dossiers de Windows 7+.

D'après le site web, il est du domaine public : "Il n'y a pas de licence en tant que telle, vous êtes libre de prendre et de faire avec le code ce que vous voulez."

Liens d'Archive.org :

1 votes

Fonctionne parfaitement ! Vous pouvez également sélectionner plusieurs dossiers en ajoutant cette ligne dans "FolderSelectDialog.cs" : public string[] FileNames { get { return ofd.FileNames ; } } et modifiez ofd.Multiselect = true ; dans le constructeur. } et modifiez ofd.Multiselect = true ; dans le constructeur.

0 votes

Malheureusement, cela ne fonctionne pas si Application.VisualStyleState est désactivé : Application.VisualStyleState = System.Windows.Forms.VisualStyles.VisualStyleState.NoneEnabl‌​ed; . Vous rencontrerez este ...

0 votes

Malheureusement, je n'ai pas eu l'occasion de faire des recherches à ce sujet (et je ne le ferai pas avant un certain temps) mais à partir d'ici : medium.com/lextm/ Ils recommandent de définir FileDialog.AutoUpgradeEnabled sur false.

7voto

Caio Proiete Points 524

Jetez un coup d'œil à la Dialogues d'Ookii qui comporte une mise en œuvre d'une boîte de dialogue de navigateur de dossiers pour Windows Forms et WPF respectivement.

enter image description here

Ookii.Dialogs.WinForms

https://github.com/augustoproiete/ookii-dialogs-winforms


Ookii.Dialogs.Wpf

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

0 votes

Bien. Note : Ookii.Dialogs nécessite Microsoft .NET Framework 4.5 ou plus. (ne peut pas être utilisé dans WinXP)

5 votes

@S.Serpooshan -- Je suppose que ça ne fonctionnera pas non plus sur mon PC Windows 3.1, non ? Mais sérieusement, en 2018, personne ne devrait penser à Windows XP de toute façon -- il est mort depuis longtemps.

0 votes

@rory.ap en fait, le principal problème de cette solution pour moi est qu'elle ne montre pas les fichiers lors de la navigation dans les dossiers. Il est parfois très utile de pouvoir voir les fichiers (par exemple les images à traiter) lorsque l'utilisateur veut sélectionner le dossier !

5voto

Simon Mourier Points 49585

Voici une version purement C#, sans nuget, qui devrait fonctionner avec toutes les versions de .NET (y compris .NET Core, .NET 5, WPF, Winforms, etc.) et utiliser Windows Vista (et supérieur) IFileDialog avec l'interface FOS_PICKFOLDERS de sorte qu'il dispose de l'interface standard Windows avec un sélecteur de dossiers.

J'ai également ajouté la fonction de WPF Window mais cela est facultatif, les lignes marquées par WPF peuvent simplement être supprimées.

l'usage :

var dlg = new FolderPicker();
dlg.InputPath = @"c:\windows\system32";
if (dlg.ShowDialog() == true)
{
    MessageBox.Show(dlg.ResultPath);
}

code :

    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Runtime.InteropServices.ComTypes;
    using System.Windows; // for WPF support
    using System.Windows.Interop;  // for WPF support

    public class FolderPicker
    {
        public virtual string ResultPath { get; protected set; }
        public virtual string ResultName { get; protected set; }
        public virtual string InputPath { get; set; }
        public virtual bool ForceFileSystem { get; set; }
        public virtual string Title { get; set; }
        public virtual string OkButtonLabel { get; set; }
        public virtual string FileNameLabel { get; set; }

        protected virtual int SetOptions(int options)
        {
            if (ForceFileSystem)
            {
                options |= (int)FOS.FOS_FORCEFILESYSTEM;
            }
            return options;
        }

        // for WPF support
        public bool? ShowDialog(Window owner = null, bool throwOnError = false)
        {
            owner ??= Application.Current.MainWindow;
            return ShowDialog(owner != null ? new WindowInteropHelper(owner).Handle : IntPtr.Zero, throwOnError);
        }

        // for all .NET
        public virtual bool? ShowDialog(IntPtr owner, bool throwOnError = false)
        {
            var dialog = (IFileOpenDialog)new FileOpenDialog();
            if (!string.IsNullOrEmpty(InputPath))
            {
                if (CheckHr(SHCreateItemFromParsingName(InputPath, null, typeof(IShellItem).GUID, out var item), throwOnError) != 0)
                    return null;

                dialog.SetFolder(item);
            }

            var options = FOS.FOS_PICKFOLDERS;
            options = (FOS)SetOptions((int)options);
            dialog.SetOptions(options);

            if (Title != null)
            {
                dialog.SetTitle(Title);
            }

            if (OkButtonLabel != null)
            {
                dialog.SetOkButtonLabel(OkButtonLabel);
            }

            if (FileNameLabel != null)
            {
                dialog.SetFileName(FileNameLabel);
            }

            if (owner == IntPtr.Zero)
            {
                owner = Process.GetCurrentProcess().MainWindowHandle;
                if (owner == IntPtr.Zero)
                {
                    owner = GetDesktopWindow();
                }
            }

            var hr = dialog.Show(owner);
            if (hr == ERROR_CANCELLED)
                return null;

            if (CheckHr(hr, throwOnError) != 0)
                return null;

            if (CheckHr(dialog.GetResult(out var result), throwOnError) != 0)
                return null;

            if (CheckHr(result.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEPARSING, out var path), throwOnError) != 0)
                return null;

            ResultPath = path;

            if (CheckHr(result.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEEDITING, out path), false) == 0)
            {
                ResultName = path;
            }
            return true;
        }

        private static int CheckHr(int hr, bool throwOnError)
        {
            if (hr != 0)
            {
                if (throwOnError)
                    Marshal.ThrowExceptionForHR(hr);
            }
            return hr;
        }

        [DllImport("shell32")]
        private static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv);

        [DllImport("user32")]
        private static extern IntPtr GetDesktopWindow();

#pragma warning disable IDE1006 // Naming Styles
        private const int ERROR_CANCELLED = unchecked((int)0x800704C7);
#pragma warning restore IDE1006 // Naming Styles

        [ComImport, Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7")] // CLSID_FileOpenDialog
        private class FileOpenDialog
        {
        }

        [ComImport, Guid("42f85136-db7e-439c-85f1-e4075d135fc8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IFileOpenDialog
        {
            [PreserveSig] int Show(IntPtr parent); // IModalWindow
            [PreserveSig] int SetFileTypes();  // not fully defined
            [PreserveSig] int SetFileTypeIndex(int iFileType);
            [PreserveSig] int GetFileTypeIndex(out int piFileType);
            [PreserveSig] int Advise(); // not fully defined
            [PreserveSig] int Unadvise();
            [PreserveSig] int SetOptions(FOS fos);
            [PreserveSig] int GetOptions(out FOS pfos);
            [PreserveSig] int SetDefaultFolder(IShellItem psi);
            [PreserveSig] int SetFolder(IShellItem psi);
            [PreserveSig] int GetFolder(out IShellItem ppsi);
            [PreserveSig] int GetCurrentSelection(out IShellItem ppsi);
            [PreserveSig] int SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);
            [PreserveSig] int GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
            [PreserveSig] int SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
            [PreserveSig] int SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);
            [PreserveSig] int SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
            [PreserveSig] int GetResult(out IShellItem ppsi);
            [PreserveSig] int AddPlace(IShellItem psi, int alignment);
            [PreserveSig] int SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
            [PreserveSig] int Close(int hr);
            [PreserveSig] int SetClientGuid();  // not fully defined
            [PreserveSig] int ClearClientData();
            [PreserveSig] int SetFilter([MarshalAs(UnmanagedType.IUnknown)] object pFilter);
            [PreserveSig] int GetResults([MarshalAs(UnmanagedType.IUnknown)] out object ppenum);
            [PreserveSig] int GetSelectedItems([MarshalAs(UnmanagedType.IUnknown)] out object ppsai);
        }

        [ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IShellItem
        {
            [PreserveSig] int BindToHandler(); // not fully defined
            [PreserveSig] int GetParent(); // not fully defined
            [PreserveSig] int GetDisplayName(SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);
            [PreserveSig] int GetAttributes();  // not fully defined
            [PreserveSig] int Compare();  // not fully defined
        }

        #pragma warning disable CA1712 // Do not prefix enum values with type name
        private enum SIGDN : uint
        {
            SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000,
            SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,
            SIGDN_FILESYSPATH = 0x80058000,
            SIGDN_NORMALDISPLAY = 0,
            SIGDN_PARENTRELATIVE = 0x80080001,
            SIGDN_PARENTRELATIVEEDITING = 0x80031001,
            SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001,
            SIGDN_PARENTRELATIVEPARSING = 0x80018001,
            SIGDN_URL = 0x80068000
        }

        [Flags]
        private enum FOS
        {
            FOS_OVERWRITEPROMPT = 0x2,
            FOS_STRICTFILETYPES = 0x4,
            FOS_NOCHANGEDIR = 0x8,
            FOS_PICKFOLDERS = 0x20,
            FOS_FORCEFILESYSTEM = 0x40,
            FOS_ALLNONSTORAGEITEMS = 0x80,
            FOS_NOVALIDATE = 0x100,
            FOS_ALLOWMULTISELECT = 0x200,
            FOS_PATHMUSTEXIST = 0x800,
            FOS_FILEMUSTEXIST = 0x1000,
            FOS_CREATEPROMPT = 0x2000,
            FOS_SHAREAWARE = 0x4000,
            FOS_NOREADONLYRETURN = 0x8000,
            FOS_NOTESTFILECREATE = 0x10000,
            FOS_HIDEMRUPLACES = 0x20000,
            FOS_HIDEPINNEDPLACES = 0x40000,
            FOS_NODEREFERENCELINKS = 0x100000,
            FOS_OKBUTTONNEEDSINTERACTION = 0x200000,
            FOS_DONTADDTORECENT = 0x2000000,
            FOS_FORCESHOWHIDDEN = 0x10000000,
            FOS_DEFAULTNOMINIMODE = 0x20000000,
            FOS_FORCEPREVIEWPANEON = 0x40000000,
            FOS_SUPPORTSTREAMABLEITEMS = unchecked((int)0x80000000)
        }
        #pragma warning restore CA1712 // Do not prefix enum values with type name
    }

résultat :

enter image description here

0 votes

Bonjour, j'essaie actuellement de faire fonctionner ce qui précède dans Visual Studio, C# 2015, .Net v4.8.04084 sous Windows 10 Pro Build 21H1 OS Build 19043.1055. Cette ligne : if (CheckHr(SHCreateItemFromParsingName(InputPath, null, typeof(IShellItem).GUID, out var item), throwOnError) != 0) return null ; par exemple retourne CS1003 C# Syntax error, ',' expected, any help would be appreciated, getting good in c# but - not that good yet

0 votes

@FalloutBoy - Si vous utilisez une ancienne version de C#, remplacez var par le type de variable de sortie (par exemple IShellItem dans ce cas) ou même le déclarer en dehors de l'appel, et non en ligne. docs.microsoft.com/fr/us/dotnet/csharp/whats-new/

0 votes

Merci Simon, j'ai finalement réussi à le faire fonctionner après avoir lu tes commentaires ici, bien que ton code fonctionne effectivement sous cette version si tu enlèves les parties WPF, il nécessite une certaine localisation des variables dans les sous-programmes - je pense que c'est cela et la syntaxe c# ultérieure qui m'a fait perdre la tête mais tout est bon maintenant.

-5voto

AHM Points 17

Cela devrait être la méthode la plus évidente et la plus directe.

using (var dialog = new System.Windows.Forms.FolderBrowserDialog())
{

   System.Windows.Forms.DialogResult result = dialog.ShowDialog();

   if(result == System.Windows.Forms.DialogResult.OK)
   {
      selectedFolder = dialog.SelectedPath;
   }

}

6 votes

FolderBrowserDialog a déjà été proposée ici plusieurs fois, et c'est la mauvaise réponse. Il s'agit d'une interface obsolète et très peu conviviale. Elle utilise SHBrowseForFolder en dessous, et même les docs indiquent _" Pour Windows Vista ou une version ultérieure, il est recommandé d'utiliser IFileDialog avec le FOS_PICKFOLDERS plutôt que l'option SHBrowseForFolder fonction. Elle utilise la boîte de dialogue Ouvrir des fichiers en mode de sélection des dossiers et constitue l'implémentation préférée."_

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