Відкрити діалогове вікно каталогу


274

Я хочу, щоб користувач обрав каталог, де буде збережений файл, який я потім генерую. Я знаю, що в WPF я повинен використовувати OpenFileDialogфайл від Win32, але, на жаль, діалогове вікно вимагає вибору файлів (файлів) - він залишається відкритим, якщо я просто натисніть кнопку ОК, не вибираючи жодного. Я міг би "зламати" функціональність, дозволяючи користувачеві вибирати файл, а потім прокреслити шлях, щоб зрозуміти, до якого каталогу він належить, але це в кращому випадку неінтуїтивно. Хтось бачив, як це робилося раніше?




Відповіді:


406

Для цього можна використовувати вбудований клас FolderBrowserDialog . Не зауважте, що він знаходиться в System.Windows.Formsпросторі імен.

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

Якщо ви хочете, щоб вікно було модальним над деяким вікном WPF, див. Питання Як використовувати FolderBrowserDialog із програми WPF .


РЕДАКТУВАННЯ: Якщо ви хочете чогось більш фантазійного, ніж звичайна, потворна Windows Forms FolderBrowserDialog, є кілька альтернатив, які дозволять замість цього використовувати діалогове вікно Vista:

  • Сторонні бібліотеки, такі як діалоги Ookii (.NET 3.5)
  • Windows API Code Pack-Shell :

    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.
Роман Старков

70
Тим не менш, чому WPF пропонує чудовий OpenFileDialog, але не OpenFolderDialog? Це не трохи дивно? Чому тут не вистачає WPF? Чи планується додати клас до цього діалогу у WPF?
Пол-Себастьян Маноле

14
Не забувайте, що FolderBrowserDialog є одноразовим.
ЛосМанос

9
Зверніть увагу, що для використання CommonOpenFileDialogвід WindowsAPICodePackвас потрібно Install-Package WindowsAPICodePack-Shell. Посилання, надане у відповіді, не перераховує це.
Микола Новак

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>

і код-позаду

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? Чи не слід змінювати сповіщення автоматичними у властивостях залежності?
Хайнзі

4
Ви можете вказати у прив'язці, коли потрібно запускати оновлення. За замовчуванням він знаходиться у програмі LostFocus, але ви можете сказати, що він також відкриє оновлення на PropertyChanged.
Олександра

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

tnx ваш шлях був найкоротшим
ehsan wwe

8

Для тих, хто не хоче створити спеціальний діалог, але все-таки вважає за краще 100% WPF спосіб і не хоче використовувати окремі 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, якби мікрософт виводив голову з дуп, але поки вони цього не зробили, це моє тимчасове рішення.


1
Це було класно. Здивований, що, схоже, ніхто більше не намагався цього зробити. Пакет NuGet, звичайно, набагато краще, але без NuGet WindowsAPICodePack це відмінний спосіб ПРАВИЛЬНІСТЬ можливості вибору папки без додавання нових пакетів / посилань.
Новичок коду

7

Щоб діалогове вікно каталогу отримати шлях до каталогу, спочатку додайте посилання System.Windows.Forms, а потім вирішіть, а потім покладіть цей код кнопкою.

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

(folderpathTB - це ім'я TextBox, куди я можу поставити шлях до папки; АБО ви також можете призначити його для змінної рядка, тобто)

    string folder = dialog.SelectedPath;

І якщо ви отримаєте FileName / path, просто зробіть це на кнопці Кнопка

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

(folderpathTB - це ім'я TextBox, куди я можу поставити шлях до файлу; АБО ви також можете призначити його для змінної рядка)

Примітка. У діалоговому вікні папок до проекту повинен бути доданий System.Windows.Forms.dll, інакше він не працює.


Дякую за вашу відповідь, але цей підхід уже пояснив @Heinzi вище.
Олександра

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- це той, кого ти хочеш.

Якщо ви хочете лише переглядач папок з діалогів Ooki і нічого іншого, тоді завантажте Source , виберіть потрібні файли для браузера папок (підказка: 7 файлів), і він добре вбудовується в .NET 4.5.2. Мені довелося додати посилання на System.Drawing. Порівняйте посилання в оригінальному проекті з вашим.

Як розібратися, які файли? Відкрийте додаток і Ookii в різних примірниках Visual Studio. Додайте VistaFolderBrowserDialog.csу свою програму та продовжуйте додавати файли, поки помилки збирання не усунуться. Ви знаходите залежності в проекті Ookii - Control-Клацніть на ту, яку ви хочете перейти до її джерела (призначений каламбур).

Ось файли, які вам потрібні, якщо ви лінуєтеся це робити ...

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.

Працює над моєю машиною [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
Це вимагає від користувача вибору файлу з папки. Якщо папка порожня, ви не можете вибрати її.
Олександру Діку

Так, я розумію, що це якесь вирішення, а не ідеальне рішення цього питання.
koberone
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.