453 Stimmen

Wie verwende ich OpenFileDialog, um einen Ordner auszuwählen?

Ich hatte vor, das folgende Projekt zu verwenden: https://github.com/scottwis/OpenFileOrFolderDialog

Allerdings gibt es ein Problem: Es verwendet die GetOpenFileName Funktion und OPENFILENAME Struktur. OPENFILENAME hat das Mitglied namens templateID der der Bezeichner für die Dialogvorlage ist. Und das Projekt enthält die res1.rc Datei und die Dialogvorlage init. Aber ich konnte nicht herausfinden, wie man diese Datei zu meinem C#-Projekt anhängen.

Gibt es eine bessere Möglichkeit, eine OpenFileDialog um Ordner auszuwählen?

525voto

Ionică Bizău Punkte 101189

Grundsätzlich benötigen Sie die FolderBrowserDialog Klasse:

Fordert den Benutzer auf, einen Ordner auszuwählen. Diese Klasse kann nicht vererbt werden.

using(var fbd = new FolderBrowserDialog())
{
    DialogResult result = fbd.ShowDialog();

    if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath))
    {
        string[] files = Directory.GetFiles(fbd.SelectedPath);

        System.Windows.Forms.MessageBox.Show("Files found: " + files.Length.ToString(), "Message");
    }
}

Wenn Sie arbeiten in WPF müssen Sie den Verweis auf System.Windows.Forms .

müssen Sie außerdem Folgendes hinzufügen using System.IO para Directory Klasse

473voto

Joe Punkte 4510

Ein Hinweis für künftige Benutzer, die die Verwendung von FolderBrowserDialog hat Microsoft einmal eine API mit dem Namen WindowsAPICodePack veröffentlicht, die einen hilfreichen Dialog mit dem Namen CommonOpenFileDialog die in eine IsFolderPicker Modus. Die API ist von Microsoft als NuGet-Paket .

Das ist alles, was ich brauchte, um die Software zu installieren und zu verwenden CommonOpenFileDialog . (NuGet verwaltet die Abhängigkeiten)

Install-Package Microsoft.WindowsAPICodePack-Shell

Für die Include-Zeile:

using Microsoft.WindowsAPICodePack.Dialogs;

Verwendung:

CommonOpenFileDialog dialog = new CommonOpenFileDialog();
dialog.InitialDirectory = "C:\\Users";
dialog.IsFolderPicker = true;
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
{
    MessageBox.Show("You selected: " + dialog.FileName);
}

78voto

Simon Mourier Punkte 122836

Hier ist eine reine C#-Version ohne Nuget, die mit allen Versionen von .NET (einschließlich .NET Core, .NET 5, WPF, Winforms usw.) funktionieren sollte und Windows Vista (und höher) verwendet IFileDialog Schnittstelle mit dem FOS_PICKFOLDERS Optionen, so dass die schöne Windows-Standard-Benutzeroberfläche für die Ordnerauswahl zur Verfügung steht.

Ich habe auch WPF's Window Typunterstützung, aber dies ist optional, die WPF-gekennzeichneten Zeilen können einfach entfernt werden.

Verwendung:

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
    }

Ergebnis:

enter image description here

68voto

Daniel Ballinger Punkte 12389

Es gibt eine hackige Lösung mit OpenFileDialog donde ValidateNames y CheckFileExists sind beide auf false gesetzt und FileName erhält einen Scheinwert, um anzuzeigen, dass ein Verzeichnis ausgewählt ist.

Ich sage "hacken", weil es für die Benutzer verwirrend ist, wie sie einen Ordner auswählen können. Sie müssen sich im gewünschten Ordner befinden und dann einfach auf Öffnen drücken, während im Dateinamen "Ordnerauswahl" steht.

C# Folder selection dialog

Dies beruht auf Datei oder Ordner aus dem gleichen Dialog auswählen von Denis Stankovski.

OpenFileDialog folderBrowser = new OpenFileDialog();
// Set validate names and check file exists to false otherwise windows will
// not let you select "Folder Selection."
folderBrowser.ValidateNames = false;
folderBrowser.CheckFileExists = false;
folderBrowser.CheckPathExists = true;
// Always default to Folder Selection.
folderBrowser.FileName = "Folder Selection.";
if (folderBrowser.ShowDialog() == DialogResult.OK)
{
    string folderPath = Path.GetDirectoryName(folderBrowser.FileName);
    // ...
}

13voto

Andrew Punkte 6861

Seltsam, dass so viele Antworten/Stimmen eingehen, aber niemand den folgenden Code als Antwort hinzufügt:

using (var opnDlg = new OpenFileDialog()) //ANY dialog
{ 
    //opnDlg.Filter = "Png Files (*.png)|*.png";
    //opnDlg.Filter = "Excel Files (*.xls, *.xlsx)|*.xls;*.xlsx|CSV Files (*.csv)|*.csv"

    if (opnDlg.ShowDialog() == DialogResult.OK)
    {
        //opnDlg.SelectedPath -- your result
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X