Verzeichnisdialog öffnen

273

Ich möchte, dass der Benutzer ein Verzeichnis auswählt, in dem eine Datei gespeichert wird, die ich dann generieren werde. Ich weiß, dass ich in WPF das OpenFileDialogvon Win32 verwenden sollte, aber leider müssen für den Dialog Dateien ausgewählt werden - es bleibt geöffnet, wenn ich einfach auf OK klicke, ohne eine auszuwählen. Ich könnte die Funktionalität "hacken", indem ich den Benutzer eine Datei auswählen und dann den Pfad entfernen lasse, um herauszufinden, zu welchem ​​Verzeichnis sie gehört, aber das ist bestenfalls nicht intuitiv. Hat jemand das schon einmal gesehen?

Alexandra
quelle
Mögliches Duplikat des Dialogfelds Ordner auswählen WPF
Entwickler
Werfen
Entwickler

Antworten:

406

Sie können hierfür die integrierte FolderBrowserDialog- Klasse verwenden. Es macht nichts, dass es im System.Windows.FormsNamespace ist.

using (var dialog = new System.Windows.Forms.FolderBrowserDialog())
{
    System.Windows.Forms.DialogResult result = dialog.ShowDialog();
}

Wenn Sie möchten, dass das Fenster über ein WPF-Fenster modal ist, lesen Sie die Frage So verwenden Sie einen FolderBrowserDialog aus einer WPF-Anwendung .


BEARBEITEN: Wenn Sie etwas ausgefalleneres als den einfachen, hässlichen Windows Forms FolderBrowserDialog möchten, gibt es einige Alternativen, mit denen Sie stattdessen das Vista-Dialogfeld verwenden können:

  • Bibliotheken von Drittanbietern, z. B. Ookii-Dialoge (.NET 3.5)
  • Die Windows API Code Pack-Shell :

    using Microsoft.WindowsAPICodePack.Dialogs;
    
    ...
    
    var dialog = new CommonOpenFileDialog();
    dialog.IsFolderPicker = true;
    CommonFileDialogResult result = dialog.ShowDialog();

    Beachten Sie, dass dieses Dialogfeld unter Betriebssystemen, die älter als Windows Vista sind, nicht verfügbar ist. Überprüfen Sie dies daher CommonFileDialog.IsPlatformSupportedzuerst.

Heinzi
quelle
78
Beachten Sie, dass dies ein schrecklicher Dialog ist. Sie können keinen Pfad kopieren und einfügen, und es werden keine bevorzugten Ordner unterstützt. Insgesamt würde ich es mit 0 von 5 bewerten und niemandem empfehlen, es jemals zu verwenden. Abgesehen davon, dass es keine vernünftige Alternative gab, bis Windows Vista den viel besseren Ordner-Dialog herausbrachte . Es gibt gute kostenlose Bibliotheken , die den guten Dialog unter Vista + und den schlechten unter XP anzeigen.
Roman Starkov
70
Warum bietet WPF einen großartigen OpenFileDialog, aber keinen OpenFolderDialog? Ist das nicht ein bisschen seltsam? Warum fehlt WPF hier? Gibt es Pläne, eine Klasse für diesen Dialog in WPF hinzuzufügen?
Paul-Sebastian Manole
14
Vergessen Sie nicht, dass FolderBrowserDialog verfügbar ist.
LosManos
9
Beachten Sie, dass Sie zur Verwendung CommonOpenFileDialogvon WindowsAPICodePackmüssen Install-Package WindowsAPICodePack-Shell. Der in der Antwort angegebene Link listet das nicht auf.
Nikola Novak
5
"Der Typ oder Namespace CommonOpenFileDialog wurde nicht gefunden". Es ist 2017 und ich kann keinen Ordner
auswählen
46

Ich habe ein UserControl erstellt, das wie folgt verwendet wird:

  <UtilitiesWPF:FolderEntry Text="{Binding Path=LogFolder}" Description="Folder for log files"/>

Die xaml-Quelle sieht folgendermaßen aus:

<UserControl x:Class="Utilities.WPF.FolderEntry"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <DockPanel>
        <Button Margin="0" Padding="0" DockPanel.Dock="Right" Width="Auto" Click="BrowseFolder">...</Button>
        <TextBox Height="Auto" HorizontalAlignment="Stretch" DockPanel.Dock="Right" 
           Text="{Binding Text, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
    </DockPanel>
</UserControl>

und der Code-Behind

public partial class FolderEntry {
    public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(FolderEntry), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    public static DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(string), typeof(FolderEntry), new PropertyMetadata(null));

    public string Text { get { return GetValue(TextProperty) as string; } set { SetValue(TextProperty, value); }}

    public string Description { get { return GetValue(DescriptionProperty) as string; } set { SetValue(DescriptionProperty, value); } }

    public FolderEntry() { InitializeComponent(); }

    private void BrowseFolder(object sender, RoutedEventArgs e) {
        using (FolderBrowserDialog dlg = new FolderBrowserDialog()) {
            dlg.Description = Description;
            dlg.SelectedPath = Text;
            dlg.ShowNewFolderButton = true;
            DialogResult result = dlg.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK) {
                Text = dlg.SelectedPath;
                BindingExpression be = GetBindingExpression(TextProperty);
                if (be != null)
                    be.UpdateSource();
            }
        }
    }
 }
adrianm
quelle
1
+1, schönes Beispiel, wie man ein UserControl schreibt. Eine Frage: Warum brauchst du be.UpdateSource? Sollten Änderungsbenachrichtigungen in Abhängigkeitseigenschaften nicht automatisch geändert werden?
Heinzi
4
Sie können in der Bindung angeben, wann die Updates ausgelöst werden sollen. Standardmäßig befindet es sich auf dem LostFocus, aber Sie können ihm auch mitteilen, dass Updates auf PropertyChanged ausgelöst werden sollen.
Alexandra
3
Die Bindung wird dann auch für jeden Tastendruck aktualisiert. Wenn der Benutzer beim Update eine Überprüfung durchführt (z. B. Directory.Exist), kann dies zu Problemen führen.
Adrianm
10

Das Ookii-Ordner-Dialogfeld finden Sie bei Nuget.

PM> Install-Package Ookii.Dialogs

Der Beispielcode lautet wie folgt.

var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
if (dialog.ShowDialog(this).GetValueOrDefault())
{
    textBoxFolderPath.Text = dialog.SelectedPath;
}
Youngjae
quelle
tnx dein Weg war am kürzesten
ehsan wwe
8

Für diejenigen, die kein benutzerdefiniertes Dialogfeld erstellen möchten, aber dennoch eine 100% WPF-Methode bevorzugen und keine separaten DDLs, zusätzlichen Abhängigkeiten oder veralteten APIs verwenden möchten, habe ich mithilfe des Dialogfelds Speichern unter einen sehr einfachen Hack entwickelt.

Keine Verwendung der Direktive erforderlich, Sie können einfach den folgenden Code kopieren und einfügen!

Es sollte immer noch sehr benutzerfreundlich sein und die meisten Leute werden es nie bemerken.

Die Idee kommt von der Tatsache, dass wir den Titel dieses Dialogfelds ändern, Dateien ausblenden und den resultierenden Dateinamen ganz einfach umgehen können.

Es ist sicher ein großer Hack, aber vielleicht macht es den Job gut für Ihren Gebrauch ...

In diesem Beispiel habe ich ein Textfeldobjekt, das den resultierenden Pfad enthält, aber Sie können die zugehörigen Zeilen entfernen und einen Rückgabewert verwenden, wenn Sie möchten ...

// Create a "Save As" dialog for selecting a directory (HACK)
var dialog = new Microsoft.Win32.SaveFileDialog();
dialog.InitialDirectory = textbox.Text; // Use current value for initial dir
dialog.Title = "Select a Directory"; // instead of default "Save As"
dialog.Filter = "Directory|*.this.directory"; // Prevents displaying files
dialog.FileName = "select"; // Filename will then be "select.this.directory"
if (dialog.ShowDialog() == true) {
    string path = dialog.FileName;
    // Remove fake filename from resulting path
    path = path.Replace("\\select.this.directory", "");
    path = path.Replace(".this.directory", "");
    // If user has changed the filename, create the new directory
    if (!System.IO.Directory.Exists(path)) {
        System.IO.Directory.CreateDirectory(path);
    }
    // Our final value is in path
    textbox.Text = path;
}

Die einzigen Probleme mit diesem Hack sind:

  • Die Schaltfläche "Bestätigen" sagt immer noch "Speichern" anstelle von "Verzeichnis auswählen", aber in einem Fall wie Minen "speichere" ich die Verzeichnisauswahl, damit es immer noch funktioniert ...
  • Das Eingabefeld sagt immer noch "Dateiname" anstelle von "Verzeichnisname", aber wir können sagen, dass ein Verzeichnis ein Dateityp ist ...
  • Es gibt immer noch ein Dropdown-Menü "Dateityp", aber der Wert lautet "Verzeichnis (* .this.directory)", und der Benutzer kann es nicht für etwas anderes ändern, funktioniert für mich ...

Die meisten Leute werden dies nicht bemerken, obwohl ich es definitiv vorziehen würde, einen offiziellen WPF-Weg zu verwenden, wenn Microsoft ihre Köpfe aus ihren Ärschen bekommen würde, aber bis sie es tun, ist das meine vorübergehende Lösung.

Olivier St-L
quelle
1
Das war cool. Überrascht, dass dies anscheinend niemand anders versucht hat. Das NuGet-Paket ist natürlich viel besser, aber ohne das NuGet WindowsAPICodePack ist dies eine hervorragende Möglichkeit, die Möglichkeit zu hacken, einen Ordner auszuwählen, ohne neue Pakete / Referenzen hinzuzufügen.
Code Novice
7

Damit der Verzeichnisdialog den Verzeichnispfad erhält, fügen Sie zuerst die Referenz System.Windows.Forms hinzu, klicken Sie dann auf Auflösen und fügen Sie diesen Code mit einem Klick auf eine Schaltfläche ein.

    var dialog = new FolderBrowserDialog();
    dialog.ShowDialog();
    folderpathTB.Text = dialog.SelectedPath;

(folderpathTB ist der Name der TextBox, in die ich den Ordnerpfad einfügen möchte, ODER Sie können ihn auch einer Zeichenfolgenvariablen zuweisen, z.

    string folder = dialog.SelectedPath;

Und wenn Sie Dateinamen / Pfad erhalten möchten, tun Sie dies einfach auf Button Click

    FileDialog fileDialog = new OpenFileDialog();
    fileDialog.ShowDialog();
    folderpathTB.Text = fileDialog.FileName;

(folderpathTB ist der Name der TextBox, in die ich den Dateipfad einfügen möchte, ODER Sie können ihn auch einer Zeichenfolgenvariablen zuweisen.)

Hinweis: Für den Ordner-Dialog muss die System.Windows.Forms.dll zum Projekt hinzugefügt werden, sonst würde es nicht funktionieren.

Zia Ur Rahman
quelle
Vielen Dank für Ihre Antwort, aber dieser Ansatz wurde bereits von @Heinzi oben erklärt.
Alexandra
5

Ich habe den folgenden Code unter dem folgenden Link gefunden ... und es hat funktioniert. Ordner-Dialog WPF auswählen

using Microsoft.WindowsAPICodePack.Dialogs;

var dlg = new CommonOpenFileDialog();
dlg.Title = "My Title";
dlg.IsFolderPicker = true;
dlg.InitialDirectory = currentDirectory;

dlg.AddToMostRecentlyUsedList = false;
dlg.AllowNonFileSystemItems = false;
dlg.DefaultDirectory = currentDirectory;
dlg.EnsureFileExists = true;
dlg.EnsurePathExists = true;
dlg.EnsureReadOnly = false;
dlg.EnsureValidNames = true;
dlg.Multiselect = false;
dlg.ShowPlacesList = true;

if (dlg.ShowDialog() == CommonFileDialogResult.Ok) 
{
  var folder = dlg.FileName;
  // Do something with selected folder string
}
Saurabh Raoot
quelle
4

Der beste Weg, um das zu erreichen, was Sie wollen, besteht darin, ein eigenes wpf-basiertes Steuerelement zu erstellen oder ein Steuerelement zu verwenden, das von anderen Personen erstellt wurde.
Warum? Da sich die Verwendung des Winforms-Dialogfelds in einer wpf-Anwendung (aus irgendeinem Grund) spürbar auf die Leistung auswirkt,
empfehle ich dieses Projekt
https://opendialog.codeplex.com/
oder Nuget:

PM> Install-Package OpenDialog

Es ist sehr MVVM-freundlich und umschließt den Winforms-Dialog nicht

bigworld12
quelle
3

Ich würde vorschlagen, das Nugget-Paket hinzuzufügen:

  Install-Package OpenDialog

Dann ist die Art und Weise, wie man es benutzt:

    Gat.Controls.OpenDialogView openDialog = new Gat.Controls.OpenDialogView();
    Gat.Controls.OpenDialogViewModel vm = (Gat.Controls.OpenDialogViewModel)openDialog.DataContext;
    vm.IsDirectoryChooser = true;
    vm.Show();

    WPFLabel.Text = vm.SelectedFilePath.ToString();

Hier ist die Dokumentation: http://opendialog.codeplex.com/documentation

Funktioniert für Dateien, Dateien mit Filter, Ordner usw.

Jose Ortega
quelle
2

Der Ookii VistaFolderBrowserDialogist der, den Sie wollen.

Wenn Sie nur den Ordner-Browser von Ooki Dialogs und nichts anderes möchten, dann laden Sie die Quelle herunter , wählen Sie die Dateien aus, die Sie für den Ordner-Browser benötigen (Hinweis: 7 Dateien), und es wird in .NET 4.5.2 einwandfrei erstellt. Ich musste einen Verweis auf hinzufügen System.Drawing. Vergleichen Sie die Referenzen im Originalprojekt mit Ihren.

Wie finden Sie heraus, welche Dateien? Öffnen Sie Ihre App und Ookii in verschiedenen Visual Studio-Instanzen. Fügen Sie VistaFolderBrowserDialog.csIhrer App hinzu und fügen Sie weitere Dateien hinzu, bis die Erstellungsfehler behoben sind. Sie finden die Abhängigkeiten im Ookii-Projekt - Strg-Klicken Sie auf diejenige, der Sie folgen möchten, um zur Quelle zurückzukehren (Wortspiel beabsichtigt).

Hier sind die Dateien, die Sie benötigen, wenn Sie zu faul sind, um das zu tun ...

NativeMethods.cs
SafeHandles.cs
VistaFolderBrowserDialog.cs
\ Interop
   COMGuids.cs
   ErrorHelper.cs
   ShellComInterfaces.cs
   ShellWrapperDefinitions.cs

Bearbeiten Sie Zeile 197 in, es VistaFolderBrowserDialog.cssei denn, Sie möchten deren einschließenResources.Resx

neue InvalidOperationException auslösen (Properties.Resources.FolderBrowserDialogNoRootFolder);

throw new InvalidOperationException("Unable to retrieve the root folder.");

Fügen Sie ihrer App den Copyright-Hinweis gemäß ihrer license.txt

Der Code in \Ookii.Dialogs.Wpf.Sample\MainWindow.xaml.csZeile 160 bis 169 ist ein Beispiel , das Sie verwenden können , aber Sie werden entfernen , müssen this,aus MessageBox.Show(this,für WPF.

Funktioniert auf meiner Maschine [TM]

CAD-Typ
quelle
2

Ich weiß, dass dies eine alte Frage ist, aber eine einfache Möglichkeit, dies zu tun, besteht darin, die von WPF bereitgestellte Option FileDialog und System.IO.Path.GetDirectory (Dateiname) zu verwenden.

Gregory Eaton
quelle
Aber dann muss der Benutzer eine Datei auswählen, obwohl er aufgefordert wird, einen Ordner auszuwählen. Ein unerfahrener Benutzer könnte an dieser Stelle HelpDesk anrufen und fragen, warum er eine Datei auswählen muss, wenn er einen Ordner auswählen muss
chriszo111
0

Keine dieser Antworten hat bei mir funktioniert (im Allgemeinen fehlte eine Referenz oder etwas in dieser Richtung).

Aber das tat ganz einfach:

Verwenden von FolderBrowserDialog in der WPF-Anwendung

Fügen Sie einen Verweis auf System.Windows.Formsdiesen Code hinzu und verwenden Sie ihn:

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

Fehlende Pakete müssen nicht aufgespürt werden. Oder fügen Sie enorme Klassen hinzu

Dies gibt mir eine moderne Ordnerauswahl, mit der Sie auch einen neuen Ordner erstellen können

Ich habe noch keine Auswirkungen auf die Bereitstellung auf anderen Computern

Nick.McDermaid
quelle
0

Sie könnten so etwas in WPF verwenden. Ich habe eine Beispielmethode erstellt. Überprüfen Sie unten.

public string getFolderPath()
{
           // Create OpenFileDialog 
           Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();

           OpenFileDialog openFileDialog = new OpenFileDialog();
           openFileDialog.Multiselect = false;

           openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
           if (openFileDialog.ShowDialog() == true)
           {
               System.IO.FileInfo fInfo = new System.IO.FileInfo(openFileDialog.FileName);
               return fInfo.DirectoryName;
           }
           return null;           
       }
koberone
quelle
1
Dazu muss der Benutzer eine Datei aus dem Ordner auswählen. Wenn der Ordner leer ist, können Sie Ihren Ordner nicht auswählen.
Alexandru Dicu
Ja, ich verstehe, dass dies eine Art Problemumgehung ist, nicht die perfekte Lösung für dieses Problem.
Oktoberone