Ouvrir la boîte de dialogue du répertoire

274

Je veux que l'utilisateur sélectionne un répertoire où sera enregistré un fichier que je générerai ensuite. Je sais que dans WPF, je devrais utiliser OpenFileDialogWin32, mais malheureusement la boîte de dialogue nécessite la sélection de fichiers - elle reste ouverte si je clique simplement sur OK sans en choisir un. Je pourrais "pirater" la fonctionnalité en laissant l'utilisateur choisir un fichier, puis supprimer le chemin pour déterminer à quel répertoire il appartient, mais cela n'est pas intuitif au mieux. Est-ce que quelqu'un a déjà vu ça?

Alexandra
la source

Réponses:

406

Vous pouvez utiliser la classe FolderBrowserDialog intégrée pour cela. Ne vous occupez pas que ce soit dans l' System.Windows.Formsespace de noms.

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

Si vous souhaitez que la fenêtre soit modale sur une fenêtre WPF, consultez la question Comment utiliser un FolderBrowserDialog à partir d'une application WPF .


EDIT: Si vous voulez quelque chose d'un peu plus sophistiqué que le FolderBrowserDialog Windows Forms simple et laid, il existe des alternatives qui vous permettent d'utiliser la boîte de dialogue Vista à la place:

  • Bibliothèques tierces, telles que les boîtes de dialogue Ookii (.NET 3.5)
  • Le code API Windows Pack-Shell :

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

    Notez que cette boîte de dialogue n'est pas disponible sur les systèmes d'exploitation antérieurs à Windows Vista, assurez-vous donc de vérifier d' CommonFileDialog.IsPlatformSupportedabord.

Heinzi
la source
78
Notez que c'est une horrible boîte de dialogue. Vous ne pouvez pas copier et coller un chemin d'accès, et il ne prend pas en charge les dossiers favoris. Dans l'ensemble, je lui donnerais un 0 sur 5 et recommanderais que personne ne l'utilise jamais. Sauf qu'il n'y avait pas d'alternative raisonnable jusqu'à ce que Windows Vista propose une boîte de dialogue de dossier bien meilleure . Il existe de bonnes bibliothèques gratuites qui affichent la bonne boîte de dialogue sous Vista + et la mauvaise sous XP.
Roman Starkov
70
Pourtant, pourquoi WPF offre-t-il un excellent OpenFileDialog mais pas OpenFolderDialog? N'est-ce pas un peu étrange? Pourquoi WPF manque ici? Est-il prévu d'ajouter une classe pour cette boîte de dialogue dans WPF?
Paul-Sebastian Manole
14
N'oubliez pas que FolderBrowserDialog est jetable.
LosManos
9
Notez que pour utiliser à CommonOpenFileDialogpartir de WindowsAPICodePackvous devez Install-Package WindowsAPICodePack-Shell. Le lien fourni dans la réponse ne répertorie pas cela.
Nikola Novak
5
Msgstr "Le type ou l 'espace de noms CommonOpenFileDialog est introuvable". Nous sommes en 2017 et je ne peux pas choisir de dossier
Nick.McDermaid
46

J'ai créé un UserControl qui est utilisé comme ceci:

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

La source xaml ressemble à ceci:

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

et le 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
la source
1
+1, bel exemple sur la façon d'écrire un UserControl. Une question: pourquoi avez-vous besoin be.UpdateSource? Les notifications de modification ne devraient-elles pas être automatiques dans les propriétés de dépendance?
Heinzi
4
Vous pouvez spécifier dans la liaison quand déclencher les mises à jour. Par défaut, il se trouve sur le LostFocus, mais vous pouvez également lui indiquer de déclencher des mises à jour sur PropertyChanged.
Alexandra
3
La liaison sera ensuite également mise à jour pour chaque frappe. Si l'utilisateur effectue une sorte de validation lors de la mise à jour (par exemple, Directory.Exist), cela peut entraîner des problèmes.
adrianm
10

La boîte de dialogue du dossier Ookii se trouve sur Nuget.

PM> Install-Package Ookii.Dialogs

Et, l'exemple de code est comme ci-dessous.

var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
if (dialog.ShowDialog(this).GetValueOrDefault())
{
    textBoxFolderPath.Text = dialog.SelectedPath;
}
Youngjae
la source
tnx votre chemin a été le plus court
ehsan wwe
8

Pour ceux qui ne veulent pas créer une boîte de dialogue personnalisée mais préfèrent toujours une méthode 100% WPF et ne veulent pas utiliser des DDL séparés, des dépendances supplémentaires ou des API obsolètes, j'ai trouvé un hack très simple en utilisant la boîte de dialogue Enregistrer sous.

Aucune directive d'utilisation requise, vous pouvez simplement copier-coller le code ci-dessous!

Il devrait toujours être très convivial et la plupart des gens ne le remarqueront jamais.

L'idée vient du fait que nous pouvons changer le titre de cette boîte de dialogue, masquer les fichiers et contourner le nom de fichier résultant assez facilement.

C'est un gros hack à coup sûr, mais peut-être qu'il fera très bien l'affaire pour votre utilisation ...

Dans cet exemple, j'ai un objet de zone de texte pour contenir le chemin résultant, mais vous pouvez supprimer les lignes associées et utiliser une valeur de retour si vous le souhaitez ...

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

Les seuls problèmes avec ce hack sont:

  • Le bouton Acknowledge dit toujours "Save" au lieu de quelque chose comme "Select directory", mais dans un cas comme les mines, je "Save" la sélection de répertoire pour qu'il fonctionne toujours ...
  • Le champ de saisie dit toujours "Nom de fichier" au lieu de "Nom de répertoire", mais on peut dire qu'un répertoire est un type de fichier ...
  • Il y a toujours une liste déroulante "Enregistrer sous type", mais sa valeur indique "Répertoire (* .this.directory)", et l'utilisateur ne peut pas le changer pour autre chose, fonctionne pour moi ...

La plupart des gens ne les remarqueront pas, même si je préférerais certainement utiliser une méthode officielle WPF si Microsoft sortait la tête de leurs fesses, mais jusqu'à ce qu'ils le fassent, c'est ma solution temporaire.

Olivier St-L
la source
1
C'était cool. Surpris que personne d'autre ne semble avoir essayé cela. Le package NuGet est bien mieux, bien sûr, mais sans le NuGet WindowsAPICodePack, c'est un excellent moyen de HACK la possibilité de sélectionner un dossier sans ajouter de nouveaux packages / références.
Code Novice
7

Pour que la boîte de dialogue de répertoire obtienne le chemin de répertoire, ajoutez d'abord la référence System.Windows.Forms, puis résolvez, puis placez ce code dans un clic de bouton.

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

(folderpathTB est le nom de TextBox où je veux mettre le chemin du dossier, OU vous pouvez aussi l'affecter à une variable de chaîne, c'est-à-dire)

    string folder = dialog.SelectedPath;

Et si vous voulez obtenir FileName / path, faites-le simplement sur Button Click

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

(folderpathTB est le nom de TextBox où je veux mettre le chemin du fichier, OU vous pouvez aussi l'affecter à une variable de chaîne)

Remarque: Pour la boîte de dialogue de dossier, le System.Windows.Forms.dll doit être ajouté au projet, sinon cela ne fonctionnerait pas.

Zia Ur Rahman
la source
Merci pour votre réponse mais cette approche a déjà été expliquée par @Heinzi ci-dessus.
Alexandra
5

J'ai trouvé le code ci-dessous sur le lien ci-dessous ... et cela a fonctionné Boîte de dialogue Sélectionner un dossier WPF

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
la source
4

La meilleure façon d'atteindre ce que vous voulez est de créer votre propre contrôle basé sur wpf, ou d'en utiliser un qui a été créé par d'autres personnes,
pourquoi? car il y aura un impact notable sur les performances lors de l'utilisation de la boîte de dialogue winforms dans une application wpf (pour une raison quelconque)
je recommande ce projet
https://opendialog.codeplex.com/
ou Nuget:

PM> Install-Package OpenDialog

il est très convivial pour MVVM et n'emballe pas la boîte de dialogue Winforms

bigworld12
la source
3

Je suggère, pour ajouter dans le paquet de pépites:

  Install-Package OpenDialog

Ensuite, la façon de l'utiliser est:

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

Voici la documentation: http://opendialog.codeplex.com/documentation

Fonctionne pour les fichiers, les fichiers avec filtre, les dossiers, etc.

Jose Ortega
la source
2

L'Ookii VistaFolderBrowserDialogest celui que vous voulez.

Si vous ne voulez que le navigateur de dossiers à partir des boîtes de dialogue Ooki et rien d'autre, téléchargez la source , choisissez les fichiers dont vous avez besoin pour le navigateur de dossiers (indice: 7 fichiers) et il se construit correctement dans .NET 4.5.2. J'ai dû ajouter une référence à System.Drawing. Comparez les références du projet d'origine aux vôtres.

Comment déterminez-vous quels fichiers? Ouvrez votre application et Ookii dans différentes instances de Visual Studio. Ajoutez VistaFolderBrowserDialog.csà votre application et continuez à ajouter des fichiers jusqu'à ce que les erreurs de construction disparaissent. Vous trouverez les dépendances dans le projet Ookii - Contrôle-cliquez sur celui que vous souhaitez suivre jusqu'à sa source (jeu de mots voulu).

Voici les fichiers dont vous avez besoin si vous êtes trop paresseux pour le faire ...

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

Modifiez la ligne 197 VistaFolderBrowserDialog.cssauf si vous souhaitez inclure leurResources.Resx

lever une nouvelle InvalidOperationException (Properties.Resources.FolderBrowserDialogNoRootFolder);

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

Ajoutez leur avis de copyright à votre application selon leur license.txt

Le code de la \Ookii.Dialogs.Wpf.Sample\MainWindow.xaml.csligne 160-169 est un exemple que vous pouvez utiliser, mais vous devrez supprimer this,de MessageBox.Show(this,pour WPF.

Fonctionne sur ma machine [TM]

CAD bloke
la source
2

Je sais que c'est une vieille question, mais un moyen simple de le faire est d'utiliser l'option FileDialog fournie par WPF et d'utiliser System.IO.Path.GetDirectory (nom de fichier).

Gregory Eaton
la source
Mais alors, l'utilisateur doit choisir un fichier même s'il lui est demandé de choisir un dossier. Un utilisateur inexpérimenté peut appeler HelpDesk à ce stade, lui demandant pourquoi il doit choisir un fichier alors qu'il doit choisir un dossier
chriszo111
0

Aucune de ces réponses n'a fonctionné pour moi (généralement il y avait une référence manquante ou quelque chose dans ce sens)

Mais cela a tout simplement fait:

Utilisation de FolderBrowserDialog dans l'application WPF

Ajoutez une référence System.Windows.Formset utilisez ce code:

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

Pas besoin de retrouver les paquets manquants. Ou ajoutez d'énormes cours

Cela me donne un sélecteur de dossier moderne qui vous permet également de créer un nouveau dossier

Je n'ai pas encore vu l'impact lors du déploiement sur d'autres machines

Nick.McDermaid
la source
0

Vous pouvez utiliser smth comme ceci dans WPF. J'ai créé un exemple de méthode. Vérifiez ci-dessous.

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
la source
1
Cela nécessite que l'utilisateur sélectionne un fichier dans le dossier. Si le dossier est vide, vous ne pouvez pas sélectionner votre dossier.
Alexandru Dicu
Oui, je comprends cela, c'est une solution de contournement, pas la solution parfaite pour ce problème.
koberone