เปิดไดอะล็อกไดเร็กทอรี


274

ฉันต้องการให้ผู้ใช้เลือกไดเรกทอรีที่ไฟล์ที่ฉันจะสร้างจะถูกบันทึกไว้ ฉันรู้ว่าใน WPF ฉันควรใช้OpenFileDialogจาก Win32 แต่น่าเสียดายที่กล่องโต้ตอบต้องมีการเลือกไฟล์ - มันยังคงเปิดอยู่ถ้าฉันคลิกตกลงโดยไม่เลือก ฉันสามารถ "แฮ็กอัพ" ฟังก์ชั่นโดยให้ผู้ใช้เลือกไฟล์จากนั้นตัดเส้นทางเพื่อหาว่าไดเรกทอรีอยู่ในไฟล์ไหน แต่ไม่ได้ใช้งานง่ายที่สุด มีใครเห็นสิ่งนี้ทำมาก่อนหรือไม่


เป็นไปได้ที่ซ้ำกันของไดอะล็อกเลือกโฟลเดอร์ WPF
นักพัฒนา


คำตอบ:


406

คุณสามารถใช้คลาสFolderBrowserDialogในตัวได้ อย่าคิดว่ามันอยู่ในSystem.Windows.Formsเนมสเปซ

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

ถ้าคุณต้องการที่หน้าต่างที่จะเป็นคำกริยาบาง WPF หน้าต่างดูคำถามวิธีการใช้ FolderBrowserDialog จากโปรแกรม


แก้ไข:ถ้าคุณต้องการบางสิ่งบางอย่างแฟนซีมากกว่าธรรมดา Windows Forms FolderBrowserDialog น่าเกลียดมีทางเลือกบางอย่างที่ช่วยให้คุณใช้กล่องโต้ตอบ Vista แทน:

  • ไลบรารีของบุคคลที่สามเช่นกล่องโต้ตอบ Ookii (.NET 3.5)
  • API ของ Windows รหัสแพ็คเชลล์ :

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

    โปรดทราบว่ากล่องโต้ตอบนี้ไม่สามารถใช้ได้กับระบบปฏิบัติการที่เก่ากว่า Windows Vista ดังนั้นโปรดตรวจสอบCommonFileDialog.IsPlatformSupportedก่อน


78
โปรดทราบว่านี่เป็นกล่องโต้ตอบที่น่ากลัว คุณไม่สามารถคัดลอกและวางเส้นทางลงและไม่สนับสนุนโฟลเดอร์โปรด โดยรวมแล้วฉันจะให้ 0 จาก 5 และไม่แนะนำใครเลย ยกเว้นว่าไม่มีทางเลือกที่เหมาะสมจนกว่า Windows Vista ออกมาพร้อมกับกล่องโต้ตอบโฟลเดอร์ที่ดีมาก มีไลบรารี่ฟรีที่ดีที่แสดงการโต้ตอบที่ดีใน Vista + และไลบราลี่ที่ไม่ดีใน XP
Roman Starkov

70
ยังทำไม WPF จึงเสนอ OpenFileDialog ที่ยอดเยี่ยม แต่ไม่มี OpenFolderDialog มันไม่แปลกเลยเหรอ? ทำไม WPF ขาดที่นี่ มีแผนที่จะเพิ่มคลาสสำหรับไดอะล็อกนี้ใน WPF หรือไม่?
พอล - เซบาสเตียน Manole

14
อย่าลืมว่า FolderBrowserDialog ถูกทิ้ง
LosManos

9
หมายเหตุว่าเพื่อให้การใช้งานCommonOpenFileDialogจากที่คุณจำเป็นต้องWindowsAPICodePack Install-Package WindowsAPICodePack-Shellลิงค์ที่ให้ไว้ในคำตอบนั้นไม่ได้ระบุไว้
Nikola Novak

5
"ไม่พบประเภทหรือเนมสเปซ CommonOpenFileDialog" มันเป็นปี 2017 และฉันไม่สามารถเลือกโฟลเดอร์ได้
Nick.McDermaid

46

ฉันสร้าง UserControl ซึ่งใช้ดังนี้:

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

แหล่ง xaml มีลักษณะดังนี้:

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

และ 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, ตัวอย่างที่ดีเกี่ยวกับวิธีการเขียน UserControl คำถามหนึ่ง: ทำไมคุณต้องการbe.UpdateSource? ไม่ควรเปลี่ยนการแจ้งเตือนโดยอัตโนมัติในคุณสมบัติการพึ่งพาหรือไม่
Heinzi

4
คุณสามารถระบุในการผูกเมื่อต้องการเริ่มการปรับปรุง โดยค่าเริ่มต้นมันอยู่ใน LostFocus แต่คุณสามารถบอกให้ทำการอัปเดตบน PropertyChanged ได้เช่นกัน
Alexandra

3
การเชื่อมโยงนั้นจะได้รับการอัพเดตสำหรับการกดแป้นทุกครั้ง หากผู้ใช้ทำการตรวจสอบในการอัพเดท (เช่น Directory.Exist) บางประเภทอาจทำให้เกิดปัญหา
adrianm


10

กล่องโต้ตอบโฟลเดอร์ Ookii อยู่ที่ Nuget

PM> Install-Package Ookii.Dialogs

และรหัสตัวอย่างมีดังนี้

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

วิธีการของคุณสั้นที่สุด
ehsan wwe

8

สำหรับผู้ที่ไม่ต้องการสร้างกล่องโต้ตอบที่กำหนดเอง แต่ยังคงต้องการวิธี WPF 100% และไม่ต้องการใช้ DDL แยกต่างหากการพึ่งพาเพิ่มเติมหรือ API ที่ล้าสมัยฉันพบแฮ็คที่ง่ายมากโดยใช้กล่องโต้ตอบบันทึกเป็น

ไม่จำเป็นต้องใช้คำสั่งคุณเพียงแค่คัดลอกโค้ดด้านล่าง!

ควรเป็นมิตรกับผู้ใช้และคนส่วนใหญ่จะไม่สังเกตเห็น

แนวคิดนี้มาจากข้อเท็จจริงที่ว่าเราสามารถเปลี่ยนชื่อของกล่องโต้ตอบนั้นซ่อนไฟล์และแก้ไขชื่อไฟล์ที่เกิดขึ้นได้อย่างง่ายดาย

มันเป็นแฮ็คขนาดใหญ่ที่แน่นอน แต่บางทีมันอาจจะทำงานได้ดีสำหรับการใช้งานของคุณ ...

ในตัวอย่างนี้ฉันมีวัตถุกล่องข้อความเพื่อให้มีเส้นทางผลลัพธ์ แต่คุณสามารถลบบรรทัดที่เกี่ยวข้องและใช้ค่าส่งคืนหากคุณต้องการ ...

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

ปัญหาเฉพาะของการแฮ็คนี้คือ:

  • ปุ่มตอบรับยังคงบอกว่า "บันทึก" แทนที่จะเป็นบางอย่างเช่น "เลือกไดเรกทอรี" แต่ในกรณีเช่นเหมืองฉัน "บันทึก" การเลือกไดเรกทอรีเพื่อให้ทำงานได้ ...
  • ช่องป้อนข้อมูลยังคงระบุว่า "ชื่อไฟล์" แทนที่จะเป็น "ชื่อไดเรกทอรี" แต่เราสามารถพูดได้ว่าไดเรกทอรีเป็นประเภทไฟล์ ...
  • ยังมีรายการดร็อปดาวน์ "บันทึกเป็นประเภท" แต่ค่าของมันระบุว่า "ไดเรกทอรี (* .this.directory)" และผู้ใช้ไม่สามารถเปลี่ยนเป็นอย่างอื่นได้ผลสำหรับฉัน ...

คนส่วนใหญ่จะไม่สังเกตเห็นสิ่งเหล่านี้ถึงแม้ว่าฉันจะชอบใช้วิธี WPF อย่างเป็นทางการแน่นอนถ้า Microsoft จะเอาหัวของพวกเขาออกจากลา แต่จนกว่าพวกเขาจะทำนั่นคือการแก้ไขชั่วคราวของฉัน


1
นี่มันเท่ห์ แปลกใจที่ไม่มีใครลองได้ แน่นอนว่าแพ็คเกจ NuGet นั้นดีกว่ามาก แต่ไม่มี NuGet WindowsAPICodePack นี่เป็นวิธีที่ยอดเยี่ยมในการแฮ็คความสามารถในการเลือกโฟลเดอร์โดยไม่ต้องเพิ่มแพ็คเกจ / การอ้างอิงใหม่
รหัสสามเณร

7

สำหรับไดอะล็อกของไดเรกตอรีที่จะได้รับเส้นทางไดเรกทอรีอันดับแรกเพิ่มการอ้างอิง System.Windows.Forms และจากนั้นแก้ไขและใส่รหัสนี้ในการคลิกปุ่ม

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

(folderpathTB เป็นชื่อของกล่องข้อความที่ฉันใส่เส้นทางโฟลเดอร์หรือคุณสามารถกำหนดให้กับตัวแปรสตริงได้เช่นกัน)

    string folder = dialog.SelectedPath;

และถ้าคุณไม่ได้รับชื่อไฟล์ / พา ธ เพียงแค่คลิกปุ่ม

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

(folderpathTB เป็นชื่อของกล่องข้อความที่ฉันใส่เส้นทางของไฟล์หรือคุณสามารถกำหนดให้กับตัวแปรสตริงได้เช่นกัน)

หมายเหตุ: สำหรับ Folder Dialog ต้องเพิ่ม System.Windows.Forms.dll ในโครงการมิฉะนั้นจะไม่สามารถใช้งานได้


ขอบคุณสำหรับคำตอบของคุณ แต่วิธีการนี้ได้รับการอธิบายโดย @Heinzi ด้านบน
Alexandra

5

ฉันพบรหัสด้านล่างในลิงค์ด้านล่าง ... และใช้งานได้ เลือกโฟลเดอร์ไดอะล็อก 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

วิธีที่ดีที่สุดในการบรรลุสิ่งที่คุณต้องการคือการสร้างการควบคุมตาม wpf ของคุณเองหรือใช้สิ่งที่คนอื่นสร้างขึ้นมา
ทำไม? เพราะจะมีผลกระทบต่อประสิทธิภาพที่เห็นได้ชัดเจนเมื่อใช้กล่องโต้ตอบ winforms ในแอปพลิเคชัน wpf (ด้วยเหตุผลบางอย่าง)
ฉันแนะนำโครงการนี้
https://opendialog.codeplex.com/
หรือ Nuget:

PM> Install-Package OpenDialog

มันเป็นมิตรกับ MVVM มากและมันไม่ได้รวมอยู่ในกล่องโต้ตอบ winforms


3

ฉันอยากจะแนะนำให้เพิ่มในแพ็คเกจนักเก็ต:

  Install-Package OpenDialog

จากนั้นวิธีใช้:

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

นี่คือเอกสารประกอบ: http://opendialog.codeplex.com/documentation

ใช้งานได้กับไฟล์ไฟล์ที่มีตัวกรองโฟลเดอร์ ฯลฯ


2

Ookii VistaFolderBrowserDialogเป็นสิ่งที่คุณต้องการ

หากคุณต้องการ Folder Browser จากOoki Dialogsและไม่มีอะไรให้ดาวน์โหลด Sourceให้เลือกไฟล์ที่คุณต้องการสำหรับ Folder browser (คำใบ้: 7 ไฟล์) และสร้างได้ดีใน. NET 4.5.2 System.Drawingผมต้องเพิ่มการอ้างอิงถึง เปรียบเทียบการอ้างอิงในโครงการต้นฉบับกับของคุณ

คุณจะรู้ได้อย่างไรว่าไฟล์ไหน เปิดแอพและ Ookii ของคุณในอินสแตนซ์ Visual Studio ที่แตกต่างกัน เพิ่มVistaFolderBrowserDialog.csในแอปของคุณและเพิ่มไฟล์ต่อไปจนกว่าข้อผิดพลาดของบิลด์จะหายไป คุณจะพบการพึ่งพาในโครงการ Ookii - ควบคุมคลิกที่สิ่งที่คุณต้องการติดตามกลับไปยังแหล่งที่มา

นี่คือไฟล์ที่คุณต้องการหากคุณขี้เกียจเกินไปที่จะทำ ...

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

แก้ไขบรรทัด 197 ในVistaFolderBrowserDialog.csเว้นแต่คุณต้องการรวมไว้Resources.Resx

โยน InvalidOperationException ใหม่ (Properties.Resources.FolderBrowserDialogNoRootFolder);

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

เพิ่มประกาศเกี่ยวกับลิขสิทธิ์ลงในแอปของคุณตามที่ระบุไว้ license.txt

รหัสใน\Ookii.Dialogs.Wpf.Sample\MainWindow.xaml.csบรรทัด 160-169 เป็นตัวอย่างที่คุณสามารถใช้ได้ แต่คุณจะต้องลบออกthis,จากMessageBox.Show(this,สำหรับ WPF

ทำงานกับ My Machine [TM]


2

ฉันรู้ว่านี่เป็นคำถามเก่า แต่วิธีง่ายๆในการทำเช่นนี้คือใช้ตัวเลือก FileDialog ที่จัดทำโดย WPF และใช้ System.IO.Path.GetDirectory (ชื่อไฟล์)


แต่จากนั้นผู้ใช้จะต้องเลือกไฟล์แม้ว่าเขาจะบอกให้เลือกโฟลเดอร์ ผู้ใช้ที่ไม่มีประสบการณ์อาจจะเรียก HelpDesk ที่จุดนี้ถามว่าทำไมเขามีการเลือกไฟล์เมื่อเขามีให้เลือกโฟลเดอร์
chriszo111

0

คำตอบเหล่านี้ไม่ได้ผลสำหรับฉัน (โดยทั่วไปมีการอ้างอิงที่ขาดหายไปหรือบางสิ่งบางอย่างตามเส้นเหล่านั้น)

แต่สิ่งนี้ทำได้ง่ายมาก:

การใช้ FolderBrowserDialog ในแอปพลิเคชัน WPF

เพิ่มการอ้างอิงถึงSystem.Windows.Formsและใช้รหัสนี้:

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

ไม่จำเป็นต้องติดตามแพ็คเกจที่ขาดหายไป หรือเพิ่มคลาสมหาศาล

สิ่งนี้ทำให้ฉันมีตัวเลือกโฟลเดอร์ที่ทันสมัยซึ่งช่วยให้คุณสร้างโฟลเดอร์ใหม่ได้

ฉันยังไม่เห็นผลกระทบเมื่อปรับใช้กับเครื่องอื่น


0

คุณสามารถใช้ smth แบบนี้ใน WPF ฉันสร้างวิธีตัวอย่างแล้ว ตรวจสอบด้านล่าง

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
สิ่งนี้ต้องการให้ผู้ใช้เลือกไฟล์จากโฟลเดอร์ หากโฟลเดอร์ว่างเปล่าคุณจะไม่สามารถเลือกโฟลเดอร์ของคุณได้
Alexandru Dicu

ใช่ฉันเข้าใจว่านี่เป็นวิธีแก้ปัญหาบางอย่างไม่ใช่วิธีแก้ปัญหาที่สมบูรณ์แบบสำหรับปัญหานี้
koberone
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.