Frage

Wenn Sie in VS .NET einen Ordner für ein Projekt auswählen, wird ein Dialogfeld angezeigt, das wie ein OpenFileDialog oder SaveFileDialog aussieht, aber so eingerichtet ist, dass nur Ordner akzeptiert werden.Seitdem 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 die Möglichkeit, einen Pfad einzugeben, nicht nutzen.

Ich bin mittlerweile fast sicher, dass es keine Möglichkeit gibt, dies aus .NET heraus zu machen, aber ich bin genauso neugierig, wie Sie das auch aus nicht verwaltetem Code machen.Wie ändern Sie den Dialog, um dieses Verhalten zu erzielen, ohne den Dialog komplett neu zu implementieren?

Ich möchte auch noch einmal betonen, dass ich den FolderBrowserDialog kenne, ihn aber manchmal nicht gerne verwende und wirklich neugierig bin, wie man einen Dialog auf diese Weise konfiguriert.Mir zu sagen, ich solle einfach den FolderBrowserDialog verwenden, hilft mir, eine konsistente Benutzeroberfläche aufrechtzuerhalten, befriedigt aber nicht meine Neugier, sodass es nicht als Antwort zählt.

Es ist auch keine Vista-spezifische Sache;Ich sehe diesen Dialog seit VS .NET 2003, daher ist er unter Win2k und WinXP machbar.Dabei handelt es sich weniger um die Frage „Ich möchte wissen, wie man das richtig macht“, sondern eher um die Frage „Ich bin neugierig darauf, seit ich es zum ersten Mal in VS 2003 machen wollte“.Ich verstehe, dass der Dateidialog von Vista eine Option dafür bietet, aber unter XP funktioniert es, also weiß ich, dass es so ist etwas damit es funktioniert.Vista-spezifische Antworten sind keine Antworten, da Vista im Fragenkontext nicht existiert.

Aktualisieren: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 hingewiesen hat (die von .NET zugegebenermaßen unangenehm ist, aber es tut Arbeit) und Mark Ransom dafür, dass er herausgefunden hat, dass MS wahrscheinlich einen benutzerdefinierten Dialog für diese Aufgabe erstellt hat.

War es hilfreich?

Lösung

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

Wenn Sie den Wert „AcceptFiles“ auf „false“ setzen, wird nur im Modus „Ordner akzeptieren“ gearbeitet.

Sie können die Quelle hier von GitHub herunterladen

Andere Tipps

Es gibt das Windows API Code Pack.Es enthält eine Menge Dinge, die mit der Shell zu tun haben, einschließlich der CommonOpenFileDialog Klasse (im Microsoft.WindowsAPICodePack.Dialogs Namensraum).Dies ist die perfekte Lösung – der übliche Öffnungsdialog, bei dem nur Ordner angezeigt werden.

Hier ist ein Beispiel für die Verwendung:

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

Leider liefert Microsoft dieses Paket nicht mehr aus, aber mehrere Personen haben inoffiziell Binärdateien auf NuGet hochgeladen.Ein Beispiel lässt sich finden Hier.Dieses Paket ist nur das Shell-spezifische Zeug.Sollten Sie es benötigen, verfügt derselbe Benutzer über mehrere andere Pakete, die mehr Funktionalität als das Originalpaket bieten.

Sie können verwenden FolderBrowserDialogEx -Ein wiederverwendbares Derivat des eingebauten OrdnerBrowserDialog.Hier können Sie einen Pfad eingeben, sogar einen UNC-Pfad.Sie können damit auch nach Computern oder Druckern suchen.Funktioniert genauso wie das integrierte FBD, aber ...besser.

(BEARBEITEN:Ich hätte darauf hinweisen sollen, dass dieser Dialog so eingestellt werden kann, dass er Dateien oder Ordner auswählt.)

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

Der Oookii.Dialogs Das Paket enthält einen verwalteten Wrapper um das neue Ordnerbrowser-Dialogfeld (Vista-Stil).Auch auf älteren Betriebssystemen verschlechtert sich die Leistung problemlos.

Verwenden Sie dazu besser den FolderBrowserDialog.

using (FolderBrowserDialog dlg = new FolderBrowserDialog())
{
    dlg.Description = "Select a folder";
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        MessageBox.Show("You selected: " + dlg.SelectedPath);
    }
}

Nach stundenlangem Suchen habe ich es gefunden diese Antwort von leetNightShade Zu eine funktionierende Lösung.

Ich glaube, dass es drei Dinge gibt, die 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 einbinden.
  2. Es wird auf den Standard zurückgegriffen FolderBrowserDialog bei Verwendung auf XP oder älteren Systemen.
  3. Der Autor erteilt die Erlaubnis, den Code für jeden Zweck zu verwenden, den Sie für angemessen halten.

    Es gibt keine Lizenz als solche, es steht Ihnen frei, mit dem Code zu machen, was Sie wollen.

Laden Sie den Code herunter Hier.

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

Dies ist nur eine Vermutung, 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 Dialog-Flags so eingestellt sind, dass die Existenz der Datei nicht überprüft wird, kann der Dialog normal geschlossen werden.

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

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 beherrsche C# nicht fließend, also erschießen Sie 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 habe ich mir den eigentlichen Dialog in Visual Studio 2005 angesehen (ich hatte vorher keinen Zugriff darauf). Es handelt sich nicht um den Standarddialog zum Öffnen von Dateien! Wenn Sie die Fenster in Spy++ untersuchen und sie mit dem Öffnen einer Standarddatei vergleichen, werden Sie feststellen, dass die Struktur und die Klassennamen nicht übereinstimmen.Wenn Sie genau hinschauen, können Sie auch einige Unterschiede zwischen den Inhalten der Dialoge erkennen.Meine Schlussfolgerung ist, dass Microsoft den Standarddialog in Visual Studio vollständig ersetzt hat, um ihm diese Funktion zu verleihen.Meine oder eine ähnliche Lösung wird so nah wie möglich sein, es sei denn, Sie sind bereit, Ihre eigene Lösung von Grund auf zu programmieren.

OK, lassen Sie mich versuchen, den ersten Punkt zu verbinden ;-) Ein wenig mit Spy ++ oder Winspector zeigt, dass das Ordnertextbox im VS-Projektort eine Anpassung des Standarddialogs ist.Es handelt sich nicht um dasselbe Feld wie das Dateinamen-Textfeld in einem Standarddateidialog wie dem in Notepad.

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

BEARBEITEN:Hier ist ein Beispiel für eine solche Anpassung und wie man sie durchführt (in Win32).nicht .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 unten im Dialog hinzugefügt wird.Siehe den Teil in Rot unten.alt text
(Quelle: apptranslator.com)

In diesem Fall besteht der angepasste Teil nur aus einer Beschriftung + einem Hyperlink, es könnte sich aber auch um einen beliebigen Dialog handeln.Es könnte eine Schaltfläche „OK“ enthalten, mit der wir nur die Ordnerauswahl bestätigen können.

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

Näheres in diesen MSDN-Artikel.

Sie können den Dateidialog in eine Unterklasse umwandeln und so Zugriff auf alle seine Steuerelemente erhalten.Jedes verfügt über einen Bezeichner, der zum Abrufen seines Fensterhandles verwendet werden kann.Sie können sie dann ein- und ausblenden, Nachrichten von ihnen über Auswahländerungen erhalten usw.usw.Es hängt alles davon ab, wie viel Aufwand Sie betreiben möchten.

Wir haben dies mithilfe der WTL-Klassenunterstützung durchgeführt und den Dateidialog so angepasst, dass er eine benutzerdefinierte Ortsleiste und Plug-in-COM-Ansichten enthält.

MSDN bietet Informationen dazu, wie man dies mit Win32 macht, Dieser CodeProject-Artikel enthält ein Beispiel, Und Dieser CodeProject-Artikel enthält ein .NET-Beispiel.

Sie können Code wie diesen verwenden

  • Der Filter ist Dateien ausblenden
  • Der Dateiname lautet „Ersten Text ausblenden“.

Zum erweiterten Ausblenden des Textfelds für den Dateinamen müssen Sie nachsehenOpenFileDialogEx

Der Code:

{
    openFileDialog2.FileName = "\r";
    openFileDialog1.Filter = "folders|*.neverseenthisfile";
    openFileDialog1.CheckFileExists = false;
    openFileDialog1.CheckPathExists = false;
}

Ich gehe davon aus, dass Sie unter Vista VS2008 verwenden?In diesem Fall denke ich, dass die FOS_PICKFOLDERS-Option wird beim Aufruf des Vista-Dateidialogs verwendet IFileDialog.Ich befürchte, dass dies im .NET-Code eine Menge kniffliger P/Invoke-Interop-Code erfordern würde, um zum Laufen zu kommen.

Erste Lösung

Ich habe dies als bereinigte Version von entwickelt Ordnerauswahldialog im .NET Win 7-Stil von Bill Seddon von lyquidity.com (Ich habe keine Zugehörigkeit).(Ich habe von seinem Code erfahren von Eine weitere Antwort auf dieser Seite).Ich habe mein eigenes geschrieben, weil seine Lösung eine zusätzliche Reflection-Klasse erfordert, die für diesen speziellen Zweck nicht benötigt wird, eine ausnahmebasierte Flusskontrolle verwendet und die Ergebnisse ihrer Reflection-Aufrufe nicht zwischenspeichert.Beachten Sie, dass die verschachtelte Statik VistaDialog Klasse ist so, dass ihre statischen Reflexionsvariablen nicht versuchen, aufgefüllt zu werden, wenn die Show Methode wird nie aufgerufen.Es greift auf den Dialog vor Vista zurück, wenn die Windows-Version nicht hoch genug ist.Sollte (theoretisch) unter Windows 7, 8, 9, 10 und höher 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 experimentieren.Es ermöglicht beispielsweise die Mehrfachauswahl im Dialogfeld im Vista-Stil.

Zweite Lösung

Simon Mourier gab eine Antwort Das zeigt, wie man genau die gleiche Aufgabe durch direktes Interop mit der Windows-API erledigt, obwohl seine Version ergänzt werden müsste, um den Dialog im älteren Stil zu verwenden, wenn er in einer älteren Windows-Version wäre.Leider hatte ich seinen Beitrag noch nicht gefunden, als ich an meiner Lösung arbeitete.Nennen Sie Ihr Gift!

Probieren Sie dieses hier aus Codeprojekt (Dank an Nitron):

Ich denke, es ist derselbe Dialog, von dem Sie sprechen. Vielleicht wäre es hilfreich, wenn Sie einen Screenshot hinzufügen würden?

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

Unter Vista können Sie verwenden IFileDialog mit festgelegter Option FOS_PICKFOLDERS.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-Versionen können Sie jederzeit auf einen Trick zurückgreifen und eine beliebige Datei im Ordner auswählen.

Ein funktionierendes Beispiel, das auf .NET Framework 2.0 und höher funktioniert, finden Sie hier Hier.

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;

Der Oookii-Dialoge für WPF Die Bibliothek verfügt über eine Klasse, die eine Implementierung eines Ordnerbrowserdialogs für WPF bereitstellt.

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

enter image description here

Es gibt auch eine Version, die damit funktioniert Windows Forms.

Ich weiß, die Frage bezog sich auf die Konfiguration von OpenFileDialog Aber da Google mich hierher gebracht hat, kann ich auch darauf hinweisen, dass Sie a verwenden sollten, wenn Sie NUR nach Ordnern suchen FolderBrowserDialog Stattdessen wie durch eine andere SO-Frage unten beantwortet

Wie gebe ich den Pfad mithilfe des Dialogfelds „Datei öffnen“ in vb.net an?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top