Apri la finestra di dialogo della directory


274

Voglio che l'utente selezioni una directory in cui verrà salvato un file che poi genererò. So che in WPF dovrei usare il OpenFileDialogda Win32, ma sfortunatamente la finestra di dialogo richiede che i file siano selezionati - rimane aperto se faccio semplicemente clic su OK senza sceglierne uno. Potrei "hackerare" la funzionalità lasciando all'utente la scelta di un file e quindi lo striping del percorso per capire a quale directory appartiene ma non è affatto intuitivo. Qualcuno l'ha mai visto prima?




Risposte:


406

A tale scopo è possibile utilizzare la classe FolderBrowserDialog integrata . Non importa che sia nello System.Windows.Formsspazio dei nomi.

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

Se si desidera che la finestra sia modale su una finestra WPF, vedere la domanda Come utilizzare un FolderBrowserDialog da un'applicazione WPF .


EDIT: Se vuoi qualcosa di un po 'più elaborato del semplice e brutto FolderBrowserDialog di Windows Form, ci sono alcune alternative che ti consentono invece di utilizzare la finestra di dialogo Vista:

  • Librerie di terze parti, come le finestre di dialogo Ookii (.NET 3.5)
  • L' API di Windows Codice Pack-Shell :

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

    Nota che questa finestra di dialogo non è disponibile sui sistemi operativi precedenti a Windows Vista, quindi assicurati di controllare CommonFileDialog.IsPlatformSupportedprima.


78
Nota che questa è una finestra di dialogo terribile. Non è possibile copiare e incollare un percorso al suo interno e non supporta le cartelle preferite. Nel complesso, lo darei uno 0 su 5 e consiglierei a nessuno di usarlo mai. Tranne il fatto che non vi era alcuna alternativa ragionevole fino a quando Windows Vista non è uscito con la finestra di dialogo delle cartelle molto migliore . Esistono buone librerie gratuite che mostrano la buona finestra di dialogo su Vista + e quella cattiva su XP.
Roman Starkov,

70
Tuttavia, perché WPF offre un ottimo OpenFileDialog ma non OpenFolderDialog? Non è strano? Perché qui manca il WPF? Ci sono piani per aggiungere una classe per questa finestra di dialogo in WPF?
Paul-Sebastian Manole,

14
Non dimenticare che FolderBrowserDialog è usa e getta.
LosManos,

9
Si noti che, al fine di utilizzare CommonOpenFileDialogda WindowsAPICodePackè necessario Install-Package WindowsAPICodePack-Shell. Il link fornito nella risposta non lo elenca.
Nikola Novak,

5
"Impossibile trovare il tipo o lo spazio dei nomi CommonOpenFileDialog". È il 2017 e non riesco a scegliere una cartella
Nick.McDermaid,

46

Ho creato un UserControl che viene utilizzato in questo modo:

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

Il sorgente xaml è simile al seguente:

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

e il 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();
            }
        }
    }
 }

1
+1, bell'esempio su come scrivere un UserControl. Una domanda: perché hai bisogno be.UpdateSource? Le notifiche di modifica non dovrebbero essere automatiche nelle proprietà di dipendenza?
Heinzi,

4
È possibile specificare nell'associazione quando attivare gli aggiornamenti. Per impostazione predefinita, è su LostFocus ma puoi dire di attivare gli aggiornamenti anche su PropertyChanged.
Alexandra,

3
L'associazione verrà quindi aggiornata per ogni sequenza di tasti. Se l'utente esegue una sorta di convalida durante l'aggiornamento (ad es. Directory.Exist) potrebbe causare problemi.
Adrianm,


10

La finestra di dialogo della cartella Ookii è disponibile su Nuget.

PM> Install-Package Ookii.Dialogs

E, il codice di esempio è il seguente.

var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
if (dialog.ShowDialog(this).GetValueOrDefault())
{
    textBoxFolderPath.Text = dialog.SelectedPath;
}

grazie a te è stata la più breve
ehsan wwe

8

Per coloro che non vogliono creare una finestra di dialogo personalizzata ma preferiscono comunque un modo WPF al 100% e non vogliono usare DDL separati, dipendenze aggiuntive o API obsolete, ho trovato un trucco molto semplice usando la finestra di dialogo Salva con nome.

Non è necessario utilizzare la direttiva, puoi semplicemente copiare e incollare il codice qui sotto!

Dovrebbe essere comunque molto intuitivo e la maggior parte delle persone non se ne accorgerà mai.

L'idea nasce dal fatto che possiamo cambiare il titolo di quella finestra di dialogo, nascondere i file e aggirare il nome del file risultante abbastanza facilmente.

È sicuramente un grande trucco, ma forse farà il lavoro bene per il tuo utilizzo ...

In questo esempio ho un oggetto casella di testo per contenere il percorso risultante, ma è possibile rimuovere le righe correlate e utilizzare un valore restituito se si desidera ...

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

Gli unici problemi con questo trucco sono:

  • Il pulsante di conferma dice ancora "Salva" invece di qualcosa come "Seleziona directory", ma in un caso come miniere "Salva" la selezione della directory in modo che funzioni ancora ...
  • Il campo di input dice ancora "Nome file" invece di "Nome directory", ma possiamo dire che una directory è un tipo di file ...
  • Esiste ancora un menu a discesa "Salva come tipo", ma il suo valore dice "Directory (* .this.directory)" e l'utente non può cambiarlo per qualcos'altro, funziona per me ...

La maggior parte delle persone non se ne accorgerà, anche se preferirei sicuramente usare un modo WPF ufficiale se Microsoft si togliesse la testa dai culi, ma fino a quando non lo farà, questa è la mia soluzione temporanea.


1
Questo è stato bello. Sorpreso che nessun altro sembra aver provato questo. Il pacchetto NuGet è ovviamente molto meglio, ma senza NuGet WindowsAPICodePack questo è un modo eccellente per HACK la possibilità di selezionare una cartella senza aggiungere nuovi pacchetti / riferimenti.
Codice novizio

7

Affinché la finestra di dialogo Directory ottenga il percorso della directory, aggiungere innanzitutto riferimento System.Windows.Forms, quindi Risolvi, quindi inserire questo codice in un clic del pulsante.

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

(folderpathTB è il nome di TextBox in cui ho inserito il percorso della cartella, OPPURE puoi assegnarlo anche a una variabile stringa, ad es.)

    string folder = dialog.SelectedPath;

E se vuoi ottenere FileName / path, fai semplicemente clic sul pulsante

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

(folderpathTB è il nome di TextBox in cui ho inserito il percorso del file, oppure puoi assegnarlo anche a una variabile stringa)

Nota: per la finestra di dialogo Cartella, System.Windows.Forms.dll deve essere aggiunto al progetto, altrimenti non funzionerebbe.


Grazie per la risposta, ma questo approccio è già stato spiegato da @Heinzi sopra.
Alexandra,

5

Ho trovato il codice qui sotto sul link sottostante ... e ha funzionato Seleziona la finestra di dialogo della cartella 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
}

4

Il modo migliore per ottenere ciò che vuoi è creare il tuo controllo basato su wpf o usarne uno creato da altre persone
perché? perché ci sarà un notevole impatto sulle prestazioni quando si utilizza la finestra di dialogo winforms in un'applicazione wpf (per qualche motivo),
consiglio questo progetto
https://opendialog.codeplex.com/
o Nuget:

PM> Install-Package OpenDialog

è molto compatibile con MVVM e non sta avvolgendo la finestra di dialogo di winform


3

Suggerirei di aggiungere nel pacchetto nugget:

  Install-Package OpenDialog

Quindi il modo di usarlo è:

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

Ecco la documentazione: http://opendialog.codeplex.com/documentation

Funziona con File, file con filtro, cartelle, ecc


2

L'Ookii VistaFolderBrowserDialogè quello che vuoi.

Se vuoi solo il Browser cartelle dalle finestre di dialogo di Ooki e nient'altro, scarica Source , seleziona i file necessari per il browser cartelle (suggerimento: 7 file) e funziona perfettamente in .NET 4.5.2. Ho dovuto aggiungere un riferimento a System.Drawing. Confronta i riferimenti nel progetto originale con i tuoi.

Come capisci quali file? Apri l'app e Ookii in diverse istanze di Visual Studio. Aggiungi VistaFolderBrowserDialog.csalla tua app e continua ad aggiungere file fino a quando gli errori di compilazione scompaiono. Trovi le dipendenze nel progetto Ookii - Control-Click su quello che vuoi seguire alla sua fonte (gioco di parole).

Ecco i file che ti servono se sei troppo pigro per farlo ...

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

Modifica la riga 197 in a VistaFolderBrowserDialog.csmeno che tu non voglia includerliResources.Resx

lanciare nuovo InvalidOperationException (Properties.Resources.FolderBrowserDialogNoRootFolder);

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

Aggiungi la loro nota sul copyright alla tua app come da loro license.txt

Il codice in \Ookii.Dialogs.Wpf.Sample\MainWindow.xaml.cslinea 160-169 è un esempio si può usare, ma sarà necessario rimuovere this,da MessageBox.Show(this,per WPF.

Funziona su My Machine [TM]


2

So che questa è una vecchia domanda, ma un modo semplice per farlo è usare l'opzione FileDialog fornita da WPF e usando System.IO.Path.GetDirectory (nome file).


Ma poi l'utente deve scegliere un file anche se gli viene detto di scegliere una cartella. Un utente inesperto potrebbe chiamare HelpDesk a questo punto, chiedendo perché debba scegliere un file quando deve scegliere una cartella
chriszo111,

0

Nessuna di queste risposte ha funzionato per me (in genere mancava un riferimento o qualcosa del genere)

Ma questo ha semplicemente fatto:

Utilizzo di FolderBrowserDialog nell'applicazione WPF

Aggiungi un riferimento System.Windows.Formse usa questo codice:

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

Non è necessario rintracciare i pacchetti mancanti. O aggiungi lezioni enormi

Questo mi dà un moderno selettore di cartelle che ti permette anche di creare una nuova cartella

Devo ancora vedere l'impatto quando distribuito su altre macchine


0

Puoi usare smth in questo modo in WPF. Ho creato un metodo di esempio. Controlla sotto.

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

1
Ciò richiede all'utente di selezionare un file dalla cartella. Se la cartella è vuota, non è possibile selezionare la cartella.
Alexandru Dicu,

Sì, lo capisco, questa è una soluzione alternativa, non la soluzione perfetta per questo problema.
Koberone,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.