Buka dialog direktori

274

Saya ingin pengguna memilih direktori tempat file yang akan saya hasilkan akan disimpan. Saya tahu bahwa di WPF saya harus menggunakan OpenFileDialogdari Win32, tetapi sayangnya dialog membutuhkan file yang akan dipilih - tetap terbuka jika saya cukup klik OK tanpa memilih satu. Saya bisa "meretas" fungsionalitas dengan membiarkan pengguna memilih file dan kemudian menghapus jalur untuk mencari tahu di mana direktori itu milik tetapi itu tidak intuitif terbaik. Adakah yang pernah melihat ini dilakukan sebelumnya?

Alexandra
sumber

Jawaban:

406

Anda dapat menggunakan kelas FolderBrowserDialog bawaan untuk ini. Jangan pedulikan itu di System.Windows.Formsnamespace.

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

Jika Anda ingin jendela menjadi modal di atas beberapa jendela WPF, lihat pertanyaan Cara menggunakan FolderBrowserDialog dari aplikasi WPF .


EDIT: Jika Anda menginginkan sesuatu yang sedikit lebih mewah daripada Windows Forms FolderBrowserDialog yang jelek, ada beberapa alternatif yang memungkinkan Anda untuk menggunakan dialog Vista sebagai gantinya:

  • Perpustakaan pihak ketiga, seperti dialog Ookii (.NET 3.5)
  • The API Windows Kode Pack-Shell :

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

    Perhatikan bahwa dialog ini tidak tersedia pada sistem operasi yang lebih tua dari Windows Vista, jadi pastikan untuk memeriksa CommonFileDialog.IsPlatformSupportedterlebih dahulu.

Heinzi
sumber
78
Perhatikan bahwa ini adalah dialog yang mengerikan. Anda tidak dapat menyalin & menempel jalur ke dalamnya, dan itu tidak mendukung folder favorit. Secara keseluruhan, saya akan memberikan 0 dari 5 dan merekomendasikan tidak ada yang pernah menggunakannya. Kecuali bahwa tidak ada alternatif yang masuk akal sampai Windows Vista keluar dengan dialog folder yang jauh lebih baik . Ada pustaka gratis yang bagus yang menunjukkan dialog yang bagus di Vista +, dan yang buruk di XP.
Roman Starkov
70
Namun, mengapa WPF menawarkan OpenFileDialog yang hebat tetapi tidak ada OpenFolderDialog? Bukankah itu agak aneh? Mengapa WPF kurang di sini? Apakah ada rencana untuk menambahkan kelas untuk dialog ini di WPF?
Paul-Sebastian Manole
14
Jangan lupa bahwa FolderBrowserDialog dapat dibuang.
LosManos
9
Perhatikan bahwa untuk menggunakan CommonOpenFileDialogdari yang WindowsAPICodePackAnda butuhkan Install-Package WindowsAPICodePack-Shell. Tautan yang disediakan dalam jawaban tidak mencantumkan itu.
Nikola Novak
5
"Tipe atau namespace CommonOpenFileDialog tidak dapat ditemukan". Ini tahun 2017 dan saya tidak dapat memilih folder
Nick.McDermaid
46

Saya membuat UserControl yang digunakan seperti ini:

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

Sumber xaml terlihat seperti ini:

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

dan kode di belakang

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();
            }
        }
    }
 }
adrianma
sumber
1
+1, contoh yang bagus tentang cara menulis UserControl. Satu pertanyaan: Mengapa Anda perlu be.UpdateSource? Tidakkah seharusnya mengubah pemberitahuan otomatis di properti ketergantungan?
Heinzi
4
Anda dapat menentukan dalam pengikatan kapan akan mengaktifkan pembaruan. Secara default ini ada di LostFocus tetapi Anda dapat memerintahkannya untuk mengaktifkan pembaruan di PropertyChanged.
Alexandra
3
Ikatan kemudian akan diperbarui untuk setiap penekanan tombol. Jika pengguna melakukan semacam validasi pada pembaruan (mis. Direktori. Ada) itu dapat menyebabkan masalah.
adrianm
10

Dialog folder Ookii dapat ditemukan di Nuget.

PM> Install-Package Ookii.Dialogs

Dan, contoh kode adalah seperti di bawah ini.

var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
if (dialog.ShowDialog(this).GetValueOrDefault())
{
    textBoxFolderPath.Text = dialog.SelectedPath;
}
Youngjae
sumber
Cara Anda terpendek
ehsan wwe
8

Bagi mereka yang tidak ingin membuat dialog khusus tetapi masih lebih suka cara WPF 100% dan tidak ingin menggunakan DDL terpisah, dependensi tambahan atau API usang, saya datang dengan hack yang sangat sederhana menggunakan dialog Save As.

Tidak perlu menggunakan arahan, Anda cukup menyalin-tempel kode di bawah ini!

Itu harus tetap sangat ramah pengguna dan kebanyakan orang tidak akan pernah menyadarinya.

Idenya berasal dari fakta bahwa kita dapat mengubah judul dialog itu, menyembunyikan file, dan mengerjakan sekitar nama file yang dihasilkan dengan cukup mudah.

Ini adalah peretasan besar, tapi mungkin itu akan melakukan pekerjaan dengan baik untuk penggunaan Anda ...

Dalam contoh ini saya memiliki objek kotak teks untuk berisi jalur yang dihasilkan, tetapi Anda dapat menghapus baris terkait dan menggunakan nilai balik jika Anda ingin ...

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

Satu-satunya masalah dengan peretasan ini adalah:

  • Tombol Acknowledge masih mengatakan "Simpan" dan bukan sesuatu seperti "Pilih direktori", tetapi dalam kasus seperti tambang saya "Simpan" pemilihan direktori sehingga masih berfungsi ...
  • Bidang input masih mengatakan "Nama file" dan bukan "Nama direktori", tetapi kita dapat mengatakan bahwa direktori adalah jenis file ...
  • Masih ada dropdown "Simpan sebagai tipe", tetapi nilainya mengatakan "Direktori (*. Direktori ini)", dan pengguna tidak dapat mengubahnya untuk sesuatu yang lain, berfungsi untuk saya ...

Kebanyakan orang tidak akan memperhatikan ini, walaupun saya pasti akan lebih suka menggunakan cara WPF resmi jika microsoft akan mengeluarkan pikiran mereka, tetapi sampai mereka melakukannya, itu adalah perbaikan sementara saya.

Olivier St-L
sumber
1
Ini keren. Terkejut bahwa tidak ada orang lain yang mencoba ini. Paket NuGet tentu saja jauh lebih baik tetapi tanpa WindowsAPICodePack NuGet ini adalah cara terbaik untuk HACK kemampuan untuk memilih folder tanpa menambahkan paket / referensi baru.
Kode Pemula
7

Untuk Direktori Dialog untuk mendapatkan Jalur Direktori, Pertama Tambahkan Sistem referensi.Windows.Forms, dan kemudian Selesaikan, kemudian masukkan kode ini dalam sebuah tombol klik.

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

(folderpathTB adalah nama TextBox di mana saya ingin meletakkan path folder, ATAU Anda dapat menetapkannya ke variabel string juga yaitu)

    string folder = dialog.SelectedPath;

Dan jika Anda ingin mendapatkan Nama File / path, Cukup lakukan ini pada Tombol Klik

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

(folderpathTB adalah nama TextBox tempat saya meletakkan path file, ATAU Anda dapat menetapkannya ke variabel string juga)

Catatan: Untuk Dialog Folder, System.Windows.Forms.dll harus ditambahkan ke proyek, jika tidak maka tidak akan berfungsi.

Zia Ur Rahman
sumber
Terima kasih atas jawaban Anda tetapi pendekatan ini sudah dijelaskan oleh @Heinzi di atas.
Alexandra
5

Saya menemukan kode di bawah ini di tautan di bawah ... dan berfungsi Pilih dialog folder 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
sumber
4

Cara terbaik untuk mencapai apa yang Anda inginkan adalah membuat kontrol berbasis wpf Anda sendiri, atau menggunakan kontrol yang dibuat oleh orang lain
mengapa? karena akan ada dampak kinerja yang nyata ketika menggunakan dialog winforms dalam aplikasi wpf (karena alasan tertentu)
saya merekomendasikan proyek ini
https://opendialog.codeplex.com/
atau Nuget:

PM> Install-Package OpenDialog

itu sangat ramah MVVM dan tidak membungkus dialog winforms

bigworld12
sumber
3

Saya sarankan, untuk menambahkan paket nugget:

  Install-Package OpenDialog

Maka cara untuk menggunakannya adalah:

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

Berikut dokumentasinya: http://opendialog.codeplex.com/documentation

Bekerja untuk File, file dengan filter, folder, dll

Jose Ortega
sumber
2

Ookii VistaFolderBrowserDialogadalah yang Anda inginkan.

Jika Anda hanya ingin Browser Folder dari Ooki Dialogs dan tidak ada yang lain kemudian unduh Source , cherry-pick file yang Anda butuhkan untuk browser Folder (petunjuk: 7 file) dan itu dibangun dengan baik di .NET 4.5.2. Saya harus menambahkan referensi ke System.Drawing. Bandingkan referensi dalam proyek asli dengan milik Anda.

Bagaimana Anda mengetahui file yang mana? Buka aplikasi dan Ookii Anda dalam berbagai contoh Visual Studio. Tambahkan VistaFolderBrowserDialog.cske aplikasi Anda dan terus menambahkan file sampai kesalahan build hilang. Anda menemukan dependensi dalam proyek Ookii - Control-Klik yang Anda ingin ikuti kembali ke sumbernya (pun intended).

Berikut adalah file yang Anda butuhkan jika Anda terlalu malas untuk melakukannya ...

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

Edit baris 197 in VistaFolderBrowserDialog.cskecuali jika Anda ingin memasukkannyaResources.Resx

melempar InvalidOperationException baru (Properties.Resources.FolderBrowserDialogNoRootFolder);

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

Tambahkan pemberitahuan hak cipta mereka ke aplikasi Anda sesuai milik mereka license.txt

Kode di \Ookii.Dialogs.Wpf.Sample\MainWindow.xaml.csbaris 160-169 adalah contoh yang dapat Anda gunakan tetapi Anda harus menghapus this,dari MessageBox.Show(this,untuk WPF.

Bekerja pada Mesin Saya [TM]

CAD cowok
sumber
2

Saya tahu ini adalah pertanyaan lama, tetapi cara sederhana untuk melakukannya adalah menggunakan opsi FileDialog yang disediakan oleh WPF dan menggunakan System.IO.Path.GetDirectory (nama file).

Gregory Eaton
sumber
Tetapi kemudian pengguna harus memilih file meskipun ia disuruh memilih folder. Seorang pengguna yang tidak berpengalaman mungkin memanggil HelpDesk pada saat ini, menanyakan mengapa ia harus memilih file ketika ia harus memilih folder
chriszo111
0

Tidak satu pun dari jawaban ini yang berhasil untuk saya (umumnya ada referensi yang hilang atau sesuatu di sepanjang baris tersebut)

Tapi ini cukup sederhana:

Menggunakan FolderBrowserDialog dalam aplikasi WPF

Tambahkan referensi ke System.Windows.Formsdan gunakan kode ini:

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

Tidak perlu melacak paket yang hilang. Atau tambahkan kelas besar

Ini memberi saya pemilih folder modern yang juga memungkinkan Anda membuat folder baru

Saya belum melihat dampaknya ketika dikerahkan ke mesin lain

Nick. McDermaid
sumber
0

Anda dapat menggunakan sesuatu seperti ini di WPF. Saya telah membuat metode contoh. Periksa di bawah.

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
sumber
1
Ini mengharuskan pengguna untuk memilih file dari folder. Jika folder kosong maka Anda tidak dapat memilih folder Anda.
Alexandru Dicu
Ya, saya mengerti, ini semacam solusi, bukan solusi yang sempurna untuk masalah ini.
koberone