Wie konfiguriere ich einen OpenFileDialog zum Auswählen von Ordnern?

250

Wenn Sie in VS .NET einen Ordner für ein Projekt auswählen, wird ein Dialogfeld angezeigt, das wie ein OpenFileDialog oder SaveFileDialog aussieht, jedoch so eingerichtet ist, dass nur Ordner akzeptiert werden. Seit ich das gesehen habe, wollte ich wissen, wie es gemacht wird. Ich kenne den FolderBrowserDialog, aber dieser Dialog hat mir nie wirklich gefallen. Es fängt zu klein an und lässt mich nicht ausnutzen, einen Pfad eingeben zu können.

Ich bin mir fast sicher, dass es in .NET keine Möglichkeit gibt, dies zu tun, aber ich bin genauso neugierig, wie Sie dies auch mit nicht verwaltetem Code tun. Wie können Sie den Dialog so ändern, dass er dieses Verhalten aufweist, ohne den Dialog von Grund auf neu zu implementieren?

Ich möchte auch noch einmal betonen, dass mir der FolderBrowserDialog bekannt ist, aber manchmal möchte ich ihn nicht verwenden, und ich bin wirklich neugierig, wie man einen Dialog auf diese Weise konfiguriert. Wenn ich nur den FolderBrowserDialog verwenden soll, kann ich eine konsistente Benutzeroberfläche beibehalten, aber meine Neugier nicht befriedigen, sodass dies nicht als Antwort gilt.

Es ist auch keine Vista-spezifische Sache; Ich habe diesen Dialog seit VS .NET 2003 gesehen, daher ist er in Win2k und WinXP möglich. Dies ist weniger eine Frage "Ich möchte wissen, wie man das richtig macht" als eine Frage "Ich war neugierig, seit ich es zum ersten Mal in VS 2003 machen wollte". Ich verstehe, dass der Dateidialog von Vista eine Option bietet, aber er funktioniert unter XP, sodass ich weiß, dass sie etwas getan haben , um ihn zum Laufen zu bringen. Vista-spezifische Antworten sind keine Antworten, da Vista im Fragenkontext nicht vorhanden ist.

Update: Ich akzeptiere die Antwort von Scott Wisniewski, weil sie ein funktionierendes Beispiel enthält, aber ich denke, Serge verdient Anerkennung dafür, dass er auf die Dialoganpassung (die zwar von .NET unangenehm ist, aber funktioniert) und Mark Ransom für das Herausfinden dieser MS Wahrscheinlich wurde ein benutzerdefinierter Dialog für diese Aufgabe erstellt.

OwenP
quelle
7
Nur eine einfache Lösung aus codeproject codeproject.com/Articles/44914/… [Der Schlüssel, um OpenFileDialog zum Auswählen von Dateien und Ordnern zu bewegen, besteht darin, die Eigenschaften ValidateNames und CheckFileExists auf false zu setzen (dialog.ValidateNames = false; dialog.CheckFileExists = false) und setzen Sie FileName auf ein spezielles Schlüsselwort, um sicherzustellen, dass Ordner ausgewählt werden (dialog.FileName = "Folder Selection";).]
Riju
3
Senden Sie dies als Antwort, es hat den Job für mein Projekt gemacht.
CigarDoug
@Riju dialog.FileName = "Folder Selection"soll dialog.FileName = "Folder Selection."mit der Nachlaufzeit sein? Trotzdem kann ich es beim zweiten Klick auf "Öffnen" nicht in Powershell zum Laufen bringen. Es wird immer wieder gesagt, dass die Datei nicht gefunden wurde, obwohl CheckFileExists angeblich falsch ist
ComradeJoecool
nvm, in Powershell-Einstellung dialog.CheckFileExists = 0statt falsch löste mein Problem
ComradeJoecool
Haben Sie die Ookii-Dialoge für WPF ausprobiert ?
C. Augusto Proiete

Antworten:

57

Ich habe ein von mir geschriebenes Dialogfeld namens OpenFileOrFolder-Dialogfeld, in dem Sie entweder einen Ordner oder eine Datei öffnen können.

Wenn Sie den Wert für AcceptFiles auf false setzen, wird nur der Modus zum Akzeptieren von Ordnern ausgeführt.

Sie können die Quelle von GitHub hier herunterladen

Scott Wisniewski
quelle
4
Sehr interessant und definitiv so kompliziert, wie ich gedacht hatte. Gibt es eine Chance, es zu kommentieren und darauf hinzuweisen, was es tut? Dies und andere Kommentare lassen mich glauben, dass MS wahrscheinlich nur einen eigenen Dialog geführt hat.
OwenP
1
Ich erhalte die folgende Fehlermeldung, wenn ich versuche, Ihre Lösung zu erstellen ... leider gehört C ++ nicht zu meinen Stärken ... Fehler 1 kann die Include-Datei 'afxres.h' nicht öffnen.
Ignacio Soler Garcia
1
@SoMoS und andere mit demselben Problem: Bearbeiten Sie in der Datei WindowsFormsApplication1.csproj die Zeile 100 so, dass sie Ihrem Setup entspricht. In meinem Fall musste ich "9.0" in "10.0" (zweimal) ändern und "(x86)" (zweimal) entfernen.
RenniePet
2
Ich habe den Code (zip) heruntergeladen und die .h (C) -Datei in gefunden und mit einem Fehler kompiliert, der die Include-Datei 'sal.h' nicht öffnen kann.
Lei Yang
2
Diese Lösung funktioniert auch nicht mit VS2010 und VS2017!
AleX_
49

Sie können FolderBrowserDialogEx verwenden - eine wiederverwendbare Ableitung des integrierten FolderBrowserDialog. Mit diesem können Sie einen Pfad eingeben, sogar einen UNC-Pfad. Sie können damit auch nach Computern oder Druckern suchen. Funktioniert genau wie die eingebaute FBD, aber ... besser.

(BEARBEITEN: Ich hätte darauf hinweisen sollen, dass in diesem Dialogfeld Dateien oder Ordner ausgewählt werden können.)

Vollständiger Quellcode (ein kurzes C # -Modul). Frei. MS-Public Lizenz.

Code zur Verwendung:

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;
}
Cheeso
quelle
7
Es tut mir leid, wenn ich beleidigt bin. Es ist nur frustrierend, eine Frage zu stellen und "Ich möchte diese spezielle Sache, nicht diese anderen Dinge" zu formulieren und die Leute fröhlich die nicht angeforderte Sache vorschlagen zu lassen. Ich wollte einen Dateibrowser-Dialog, keinen Ordner-Browser-Dialog.
OwenP
15
Die Art und Weise, wie die Frage formuliert ist, klingt für mich so, als würde sie nach einem Ordnerauswahldialog fragen - ist das nicht der Fall? Wie auch immer, genau das habe ich gesucht +1
Tim
Auf jeden Fall die beste Antwort bisher
Vasil Popov
1
Das ändert nichts an der Tatsache, dass die Antwort immer noch eine reine Linkantwort ist. Das Zeigen der Verwendung von Code, der in einer externen Ressource gehostet wird, ist nicht mehr hilfreich, wenn auch dieser Link vorübergehend oder dauerhaft nicht mehr verfügbar ist. Die Regeln gibt es aus einem Grund, und dieser Beitrag steht im Widerspruch zu diesen Regeln.
Unsichtbarer
1
Ich habe mir diese Antwort angesehen und sie verweist anscheinend nicht auf eine externe Ressource. So „jede andere Antwort“ ist eindeutig falsch. Wenn Sie das Gefühl haben, dass ich überreagiere, sollten Sie vielleicht ein Problem bei Meta ansprechen, um die Regeln zu besprechen. Ich werde nicht. Ich werde sie nur anwenden.
Unsichtbarer
48

Es gibt das Windows API Code Pack. Es gibt viele Shell-bezogene Dinge, einschließlich der CommonOpenFileDialogKlasse (im Microsoft.WindowsAPICodePack.DialogsNamespace). Dies ist die perfekte Lösung - der übliche offene Dialog, in dem nur Ordner angezeigt werden.

Hier ist ein Beispiel für die Verwendung:

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

Leider wird dieses Paket von Microsoft nicht mehr ausgeliefert, aber mehrere Personen haben inoffiziell Binärdateien auf NuGet hochgeladen. Ein Beispiel finden Sie hier . Dieses Paket ist nur das Shell-spezifische Zeug. Falls Sie es benötigen, verfügt derselbe Benutzer über mehrere andere Pakete, die mehr Funktionen im Originalpaket bieten.

Ken Wayne VanderLinde
quelle
1
Mir war nicht bewusst, dass dies im Windows API Code Pack enthalten ist - danke, dass Sie darauf hingewiesen haben.
Patrick Klug
10
Die CommonOpenFileDialog-Klasse ist nur unter Windows Vista oder höher vorhanden, daher wird bei älteren Betriebssystemen eine Ausnahme ausgelöst
Rachel,
1
Können Sie bitte angeben, wie auf das Windows API Code Pack verwiesen wird?
Jeff
1
Die Archivgalerie wurde eingestellt. , oder so sagt der Link .. Könnte dies der neue Ort dafür sein?
Standard
3
Die CommonOpenFileDialog-Klasse befindet sich übrigens im Microsoft.WindowsAPICodePack.Dialogs-Namespace (es hat eine Weile gedauert, bis ich sie gefunden habe).
Morgb
35

Das Ookii.Dialogs- Paket enthält einen verwalteten Wrapper um den neuen Ordnerdialog (im Vista-Stil). Es verschlechtert sich auch auf älteren Betriebssystemen.

Christian Klauser
quelle
2
Cool, es ist Open Source im BSD-Stil!
Roman
7
Das einzige Problem ist, dass ich das .net Framework-Clientprofil nicht als Ziel verwenden darf.
Kugel
2
Sehr schöne Lösung. Dies ist meiner Meinung nach die beste Antwort. Genau das, wonach ich seit 3 ​​Jahren gesucht habe.
Samuel
1
Ein weiteres Problem bei dieser Lösung: Der Benutzer kann keinen nicht vorhandenen Pfad einfügen. Ein kleiner, vergleichsweise, aber immer noch schade.
Roman Starkov
1
Beste praktische Antwort für diejenigen, die einen OpenFileDialogOrdner-Dialog im Stil wünschen .
Aqua
27

Verwenden Sie dafür besser den FolderBrowserDialog.

using (FolderBrowserDialog dlg = new FolderBrowserDialog())
{
    dlg.Description = "Select a folder";
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        MessageBox.Show("You selected: " + dlg.SelectedPath);
    }
}
Ryan Farley
quelle
9
Mir ist bewusst, dass es besser ist , einen FolderBrowserDialog zu verwenden. Ich bin gespannt, wie es trotzdem gemacht wurde. Der FolderBrowserDialog stinkt sowieso in vielerlei Hinsicht; Selbst in Vista gibt es keine Ortsleiste. Komisch, wie wenn es besser ist, hat MS es bisher in 3 VS-Versionen vermieden.
OwenP
24
Der FolderBrowserDialog weist viele Usability-Probleme auf. Ich würde nicht in Betracht ziehen, es tatsächlich in eine Anwendung aufzunehmen. Siehe meinen Beitrag für einen Dialog, der viel bessere Benutzerfreundlichkeit hat
Scott Wisniewski
6
FolderBrowserDialog erlaubt nicht: - vollständige Pfade in das Textfeld unten
einzugeben
89
Der FolderBrowserDialog ist ein wirklich schreckliches Stück Benutzeroberfläche.
Mackenir
32
Im Ernst, Leute, BITTE hör auf, diesen nervigen Dialog in deine Anwendungen zu integrieren. Es hat eine sehr schlechte Benutzeroberfläche, wie in früheren Kommentaren hervorgehoben.
Roman
23

Nach stundenlangem Suchen fand ich diese Antwort von leetNightShade auf eine funktionierende Lösung .

Es gibt drei Dinge, von denen ich glaube, dass sie diese Lösung viel besser machen als alle anderen.

  1. Es ist einfach zu bedienen. Sie müssen lediglich zwei Dateien (die ohnehin zu einer kombiniert werden können) in Ihr Projekt aufnehmen.
  2. Bei Verwendung auf XP oder älteren Systemen wird auf den Standard- FolderBrowserDialog zurückgegriffen .
  3. Der Autor erteilt die Erlaubnis, den Code für jeden Zweck zu verwenden, den Sie für geeignet halten.

    Es gibt keine Lizenz als solche, die Sie frei nehmen und mit dem Code machen können, was Sie wollen.

Laden Sie den Code hier herunter .

Alex Essilfie
quelle
@MattDavis: Ich habe bestätigt, dass es unter .NET Framework 4.0 (sowohl Standard- als auch Client-Profil) funktioniert. Stellen Sie einfach sicher, dass Sie sowohl FolderSelectDialog.cs als auch Reflector.cs zu Ihrem Projekt hinzugefügt haben. Eines jedoch ... laufen Sie unter Windows 8? Ich habe auf einem Win7-Computer getestet.
Alex Essilfie
@ Alex Essilfie, du bist richtig. Ich muss etwas falsch gemacht haben, als ich es in mein Projekt gezogen habe. Ich werde meinen früheren Kommentar aus Gründen der Klarheit löschen.
Matt Davis
Ich habe mehrere Optionen durchlaufen und denke, diese ist die beste. Empfehlen.
Jaded
Arbeitete in Windows 10 für mich. Gute einfache Lösung
David Wilton
müssen das Failover in älteren Systemen respektieren
Mike M
17

Exakte Audiokopie funktioniert unter Windows XP auf diese Weise. Das Standarddialogfeld zum Öffnen von Dateien wird angezeigt, aber das Feld Dateiname enthält den Text "Dateiname wird ignoriert".

Ich rate hier nur, aber ich vermute, dass die Zeichenfolge jedes Mal in das Bearbeitungssteuerelement des Kombinationsfelds eingefügt wird, wenn eine wesentliche Änderung am Dialogfeld vorgenommen wird. Solange das Feld nicht leer ist und die Dialogflags so eingestellt sind, dass die Existenz der Datei nicht überprüft wird, kann der Dialog normal geschlossen werden.

Edit: das ist viel einfacher als ich dachte. Hier ist der Code in C ++ / MFC, den Sie in die Umgebung Ihrer Wahl übersetzen können.

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

Bearbeiten 2: Dies sollte die Übersetzung in C # sein, aber ich spreche nicht fließend C #, also erschieß mich nicht, wenn es nicht funktioniert.

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
}

Bearbeiten 3: Schließlich wurde der betreffende Dialog in Visual Studio 2005 betrachtet (ich hatte zuvor keinen Zugriff darauf). Es ist nicht der Standarddialog zum Öffnen von Dateien! Wenn Sie die Fenster in Spy ++ überprüfen und mit einer geöffneten Standarddatei vergleichen, werden Sie feststellen, dass die Struktur- und Klassennamen nicht übereinstimmen. Wenn Sie genau hinschauen, können Sie auch einige Unterschiede zwischen den Inhalten der Dialoge feststellen. Mein Fazit ist, dass Microsoft das Standarddialogfeld in Visual Studio vollständig ersetzt hat, um ihm diese Funktion zu geben. Meine Lösung oder ähnliches wird so nah wie möglich sein, es sei denn, Sie sind bereit, Ihre eigene von Grund auf neu zu codieren.

Mark Ransom
quelle
17

OK, lassen Sie mich versuchen, den ersten Punkt zu verbinden ;-) Wenn Sie ein wenig mit Spy ++ oder Winspector spielen, wird angezeigt, dass das Textfeld Ordner im VS-Projektspeicherort eine Anpassung des Standarddialogs ist. Es ist nicht dasselbe Feld wie das Dateinamen-Textfeld in einem Standarddatendialog wie dem im Editor.

Von da an versteckt VS die Dateinamen- und Dateityp-Textfelder / Comboboxen und verwendet eine benutzerdefinierte Dialogvorlage, um einen eigenen Teil am unteren Rand des Dialogfelds hinzuzufügen.

BEARBEITEN: Hier ist ein Beispiel für eine solche Anpassung und wie sie durchgeführt wird (in Win32, nicht in .NET):

m_ofn ist die OPENFILENAME-Struktur, die dem Dateidialog zugrunde liegt. Fügen Sie diese 2 Zeilen hinzu:

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

Dabei ist IDD_FILEDIALOG_IMPORTXLIFF eine benutzerdefinierte Dialogvorlage, die am unteren Rand des Dialogfelds hinzugefügt wird. Siehe den Teil in rot unten. (Quelle: apptranslator.com )Alt-Text

In diesem Fall ist das benutzerdefinierte Teil nur eine Beschriftung + ein Hyperlink, es kann sich jedoch um einen beliebigen Dialog handeln. Es könnte eine OK-Schaltfläche enthalten, mit der wir nur die Ordnerauswahl überprüfen können.

Aber wie wir einige der Steuerelemente im Standardteil des Dialogs entfernen würden, weiß ich nicht.

Weitere Details in diesem MSDN-Artikel .

Serge Wautier
quelle
1
Das klingt nach Erklärungen, die ich in der Vergangenheit gehört habe, aber ich habe noch nie eine Demonstration des Konzepts gesehen. Gibt es in der MSDN-Dokumentation exemplarische Vorgehensweisen dazu?
OwenP
10

Sie können den Dateidialog in Unterklassen unterteilen und Zugriff auf alle Steuerelemente erhalten. Jeder hat eine Kennung, mit der sein Fensterhandle abgerufen werden kann. Sie können sie dann ein- und ausblenden, Nachrichten über Auswahländerungen usw. usw. von ihnen erhalten. Es hängt alles davon ab, wie viel Aufwand Sie unternehmen möchten.

Wir haben die WTL-Klassenunterstützung verwendet und den Dateidialog so angepasst, dass er eine benutzerdefinierte Platzierungsleiste und Plug-in-COM-Ansichten enthält.

MSDN enthält Informationen dazu unter Verwendung von Win32. Dieser CodeProject-Artikel enthält ein Beispiel und dieser CodeProject-Artikel enthält ein .NET-Beispiel .

Jeff Yates
quelle
10

Sie können Code wie diesen verwenden

  • Der Filter ist Dateien ausblenden
  • Der Dateiname lautet "Erster Text ausblenden"

Um das Ausblenden des Textfelds für den Dateinamen zu erweitern, müssen Sie sich OpenFileDialogEx ansehen

Der Code:

{
    openFileDialog2.FileName = "\r";
    openFileDialog1.Filter = "folders|*.neverseenthisfile";
    openFileDialog1.CheckFileExists = false;
    openFileDialog1.CheckPathExists = false;
}
Avram
quelle
Einfach und ist das, was ich für Windows 7+ brauche
Hao Nguyen
Auch OFN_NOVALIDATE ist in Flags erforderlich
Goblin Alchemist
5

Ich nehme an, Sie verwenden Vista mit VS2008? In diesem Fall denke ich, dass die Option FOS_PICKFOLDERS verwendet wird, wenn der Vista- Dateidialog IFileDialog aufgerufen wird . Ich befürchte, dass dies in .NET-Code viel knorrigen P / Invoke-Interop-Code beinhalten würde, um zu funktionieren.

Duncan Smart
quelle
1
Vista-spezifisch; Ich habe dies zum ersten Mal unter VS 2003 unter Windows XP gesehen.
OwenP
2

Erste Lösung

Ich habe dies als bereinigte Version des Ordnerauswahldialogs im .NET Win 7-Stil von Bill Seddon von lyquidity.com entwickelt (ich habe keine Zugehörigkeit). (Ich habe von seinem Code aus einer anderen Antwort auf dieser Seite erfahren ). Ich habe meine eigene geschrieben, weil seine Lösung eine zusätzliche Reflection-Klasse erfordert, die für diesen fokussierten Zweck nicht benötigt wird, eine ausnahmebasierte Flusssteuerung verwendet und die Ergebnisse ihrer Reflection-Aufrufe nicht zwischenspeichert. Beachten Sie, dass die verschachtelte statische VistaDialogKlasse so ist, dass ihre statischen Reflexionsvariablen nicht versuchen, gefüllt zu werden, wenn die ShowMethode nie aufgerufen wird. Es wird auf das Dialogfeld vor Vista zurückgegriffen, wenn die Windows-Version nicht hoch genug ist. Sollte unter Windows 7, 8, 9, 10 und höher (theoretisch) funktionieren.

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

Es wird wie folgt in einem Windows Form verwendet:

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

Sie können natürlich mit den Optionen und den verfügbaren Eigenschaften herumspielen. Beispielsweise ermöglicht es die Mehrfachauswahl im Dialogfeld im Vista-Stil.

Zweite Lösung

Simon Mourier gab eine Antwort , die zeigt, wie genau derselbe Job mit Interop direkt gegen die Windows-API ausgeführt werden kann, obwohl seine Version ergänzt werden müsste, um den älteren Dialog zu verwenden, wenn er in einer älteren Windows-Version verwendet wird. Leider hatte ich seinen Posten noch nicht gefunden, als ich meine Lösung ausgearbeitet hatte. Nennen Sie Ihr Gift!

ErikE
quelle
Ähnliches Anwendungsbeispiel zum Aufrufen dieses feinen Dialogfelds als Dialogfeld (z. B. von Apps vom Konsolentyp) mit leerem Handle: Kompiliert sofort: var dialog = new FolderSelectDialog {InitialDirectory = "C: \\", Title = "Wählen Sie a Ordner zum Importieren von Musik aus "}; if (dialog.Show ()) {string myFolder = dialog.FileName; }
Philm
Hinweis: Mein Verwendungsbeispiel als Kommentar ist daher schwer zu lesen: Wichtigste Änderung des ursprünglichen Verwendungsbeispiels: Verwenden Sie ein Komma zwischen InitialDirectory und Title.
Philm
1

Probieren Sie dieses von Codeproject aus (Gutschrift an Nitron):

Ich denke, es ist der gleiche Dialog, über den Sie sprechen - vielleicht würde es helfen, wenn Sie einen Screenshot hinzufügen?

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] = {'\0'};
        if(::SHGetPathFromIDList(pIDL, buffer) != 0)
        {
            // Set the string value.
            folderpath = buffer;
            retVal = true;
        }       

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

    ::OleUninitialize();

    return retVal;
}
Dämoncodemonkey
quelle
images.google.com/… Recherchieren Sie, wenn Sie sich nicht sicher sind. Ich habe beschrieben, was ich wollte, und FolderBrowserDialog wurde bereits als Antwort disqualifiziert.
OwenP
"Ich kenne den FolderBrowserDialog, aber dieser Dialog hat mir nie wirklich gefallen. Er beginnt zu klein und lässt mich nicht die Möglichkeit nutzen, einen Pfad einzugeben." Recherchiere selbst - du kannst dort einen Pfad eingeben. Wie auch immer, ich denke, es ist eine zweideutige Frage, also viel Glück damit.
Demoncodemonkey
@demoncodemonkey: Sie können keinen Teil des Pfads eingeben und dann zum gewünschten Ziel navigieren. Bei weitem nicht so bequem wie die Optionen, die der FileOpenDialog bietet.
Treb
1

Unter Vista können Sie IFileDialog mit dem Optionssatz FOS_PICKFOLDERS verwenden. Dadurch wird ein OpenFileDialog-ähnliches Fenster angezeigt, in dem Sie Ordner auswählen können:

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

Bei älteren Windows können Sie bei der Auswahl einer beliebigen Datei im Ordner immer auf Tricks zurückgreifen.

Ein Arbeitsbeispiel für .NET Framework 2.0 und höher finden Sie hier .

Josip Medved
quelle
1

Sie können Code wie diesen verwenden

Der Filter ist eine leere Zeichenfolge. Der Dateiname ist AnyName, aber nicht leer

        openFileDialog.FileName = "AnyFile";
        openFileDialog.Filter = string.Empty;
        openFileDialog.CheckFileExists = false;
        openFileDialog.CheckPathExists = false;
Lantran
quelle
6
Ich weiß, dass dies ein alter Beitrag ist, aber für alle, die dies ausprobieren möchten, funktioniert er nur, wenn das Verzeichnis, das Sie öffnen möchten, absolut keine untergeordneten Verzeichnisse enthält. Wenn ich also möchte, dass mein Benutzer zu einem Ordner navigiert und diesen auswählt und den Ordnerpfad in ein Textfeld einfügt, kann der Benutzer niemals C: \ SomeParentDir auswählen, wenn das Verzeichnis C: \ SomeParentDir \ SomeChildDir vorhanden ist, da "Öffnen" ausgewählt ist "bringt Sie nur zum untergeordneten Verzeichnis.
Jim
Netter Versuch .. aber dies führt zu einer schrecklichen Benutzeroberfläche, da "AnyFile" im Textfeld nur darauf wartet, dass der Benutzer seinen Text überschreibt. Ansonsten kann der Benutzer auch Dateien auswählen - nicht gut genug. aber netter Versuch ..
GY
-1

Ich weiß, dass die Frage bei der Konfiguration von war, OpenFileDialogaber da Google mich hierher gebracht hat, kann ich auch darauf hinweisen, dass Sie, wenn Sie NUR nach Ordnern suchen, stattdessen ein verwenden sollten, FolderBrowserDialogwie von einer anderen SO-Frage unten beantwortet

Wie kann ich den Pfad mithilfe des Dialogfelds "Datei öffnen" in vb.net angeben?

AltF4_
quelle
Irreführend. 1) Es ist nicht die einzige Wahl; 2) In den meisten Fällen ist es keine gute Wahl. Dennoch erfordert es den geringsten Code, der durch mehr Zeit für den Endbenutzer gehandelt wird.
Miau Katze 2012