Диалог выбора папки WPF - PullRequest
       57

Диалог выбора папки WPF

61 голосов
/ 24 октября 2010

Я разрабатываю приложение WPF4, и в моем приложении мне нужно позволить пользователю выбрать папку, в которой приложение будет что-то хранить (файлы, сгенерированные отчеты и т. Д.).

Мои требования:

  • Возможность просмотра стандартного дерева папок

  • Возможность выбрать папку

  • Внешний вид WPF, этот диалог должен выглядеть как часть современного приложения, разработанного для Windows Vista / 7, а не Windows 2000 или даже Win9x.

Как я понимаю, до 2010 года (.Net 4.0) не будет стандартного диалогового окна папок, но, возможно, в версии 4.0 будут некоторые изменения?

Или все, что нужно сделать, это использовать диалог старой школы WinForms? Если это единственный способ сделать то, что мне нужно, как я могу приблизить его к стилю Vista / 7, а не к Win9x?

На некоторых форумах я видел реализацию таких диалогов, но со старыми уродливыми иконками в стиле Windows 95. Это действительно не очень хорошо выглядит.

Ответы [ 9 ]

100 голосов
/ 18 июля 2013

Поваренная книга Windows Presentation Foundation 4.5 от Павла Йосифовича на странице 155 в разделе «Использование общих диалоговых окон» гласит:

«Как насчет выбора папки (вместофайлы)? OpenFileDialog WPF не поддерживает это. Одним из решений является использование класса FolderBrowseDialog в Windows Forms. Еще одно хорошее решение - использовать описанный ниже пакет API Windows API. "

Я загрузил APIПакет кодов из Пакет кодов Windows® API для Microsoft® .NET Framework Пакет кодов Windows API: Где это? , затем добавленссылки на Microsoft.WindowsAPICodePack.dll и Microsoft.WindowsAPICodePack.Shell.dll на мой проект WPF 4.5.

Пример:

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
}
21 голосов
/ 24 октября 2010

Я написал об этом в своем блоге очень давно, поддержка WPF общих файловых диалогов действительно плохая (или, по крайней мере, была в 3.5, я не проверял в версии 4) - но это легко обойти.

Вам необходимо добавить правильный манифест в ваше приложение - это даст вам окна сообщений в современном стиле и браузер папок (WinForms FolderBrowserDialog), но не диалоги открытия / сохранения файла WPF, это описано в этих 3 постах (если вы не заботятся о объяснении и только хотят, чтобы решение пошло непосредственно к 3-му):

К счастью, диалоги открытия / сохранения представляют собой очень тонкие обертки вокруг Win32 API, которые легко вызвать с помощью правильных флагов, чтобы получить стиль Vista / 7 (после установки манифеста)

10 голосов
/ 23 июля 2016

Добавить Windows API Code Pack-Shell в ваш проект

using Microsoft.WindowsAPICodePack.Dialogs;

...

var dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
CommonFileDialogResult result = dialog.ShowDialog();
5 голосов
/ 02 апреля 2014

MVVM + WinForms FolderBrowserDialog как поведение

public class FolderDialogBehavior : Behavior<Button>
{
    public string SetterName { get; set; }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Click += OnClick;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.Click -= OnClick;
    }

    private void OnClick(object sender, RoutedEventArgs e)
    {
        var dialog = new FolderBrowserDialog();
        var result = dialog.ShowDialog();
        if (result == DialogResult.OK && AssociatedObject.DataContext != null)
        {
            var propertyInfo = AssociatedObject.DataContext.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(p => p.CanRead && p.CanWrite)
            .Where(p => p.Name.Equals(SetterName))
            .First();

            propertyInfo.SetValue(AssociatedObject.DataContext, dialog.SelectedPath, null);
        }
    }
}

Использование

     <Button Grid.Column="3" Content="...">
            <Interactivity:Interaction.Behaviors>
                <Behavior:FolderDialogBehavior SetterName="SomeFolderPathPropertyName"/>
            </Interactivity:Interaction.Behaviors>
     </Button>

Пост блога: http://kostylizm.blogspot.ru/2014/03/wpf-mvvm-and-winforms-folder-dialog-how.html

5 голосов
/ 24 октября 2010

Microsoft.Win32.OpenFileDialog - это стандартный диалог, который используется любым приложением в Windows. Ваш пользователь не будет удивлен его внешним видом при использовании WPF в .NET 4.0

Диалог был изменен в Vista. WPF в .NET 3.0 и 3.5 все еще использовал устаревшее диалоговое окно, но это было исправлено в .NET 4.0. Я могу только догадываться, что вы начали эту тему, потому что вы видите этот старый диалог. Что, вероятно, означает, что вы на самом деле запускаете программу, нацеленную на 3.5. Да, оболочка Winforms сделала обновления и показывает версию Vista. Класс System.Windows.Forms.OpenFileDialog, вам необходимо добавить ссылку на System.Windows.Forms.

4 голосов
/ 09 мая 2018

Если вы не хотите использовать Windows Forms или редактировать файлы манифеста, я пришел к очень простому хаку, используя диалог SaveAs в WPF для фактического выбора каталога.

Использование директивы не требуется, вы можете просто скопировать и вставить приведенный ниже код!

Это все еще должно быть очень удобно, и большинство людей никогда не заметят.

Идея исходит из того факта, что мы можем легко изменить заголовок этого диалога, скрыть файлы и обойти полученное имя файла.

Это большой взлом, но, возможно, он отлично подойдет для вашего использования ...

В этом примере у меня есть объект текстового поля, в котором содержится результирующий путь, но вы можете удалить связанные строки и использовать возвращаемое значение, если хотите ...

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

Единственные проблемы с этим хаком:

  • Кнопка подтверждения по-прежнему говорит «Сохранить» вместо чего-то вроде «Выбрать каталог», но в случае, например мины, я «Сохранить» выбор каталога, чтобы он все еще работал ...
  • Поле ввода по-прежнему говорит «Имя файла» вместо «Имя каталога», но мы можем сказать, что каталог - это тип файла ...
  • Все еще есть выпадающий список "Сохранить как тип", но его значение говорит "Directory (* .this.directory)", и пользователь не может изменить его на что-то другое, у меня работает ...

Большинство людей этого не заметят, хотя я бы определенно предпочел использовать официальный способ WPF, если бы Майкрософт вытащил свои головы из задниц, но пока они этого не сделают, это мое временное исправление.

2 голосов
/ 04 октября 2018

Ookii Dialogs для WPF имеет класс VistaFolderBrowserDialog, который обеспечивает полную реализацию диалогового окна браузера папок для WPF.

https://github.com/caioproiete/ookii-dialogs-wpf

enter image description here

Существует также версия, которая работает с Windows Forms .

2 голосов
/ 09 марта 2015

Исходя из ответа Оюна, лучше использовать свойство зависимости для FolderName.Это позволяет (например) привязку к подсвойствам, что не работает в оригинале.Кроме того, в моей скорректированной версии диалоговое окно показывает выбор начальной папки.

Использование в XAML:

<Button Content="...">
   <i:Interaction.Behaviors>
      <Behavior:FolderDialogBehavior FolderName="{Binding FolderPathPropertyName, Mode=TwoWay}"/>
    </i:Interaction.Behaviors>
</Button>

Код:

using System.Windows;
using System.Windows.Forms;
using System.Windows.Interactivity;
using Button = System.Windows.Controls.Button;

public class FolderDialogBehavior : Behavior<Button>
{
    #region Attached Behavior wiring
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Click += OnClick;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.Click -= OnClick;
        base.OnDetaching();
    }
    #endregion

    #region FolderName Dependency Property
    public static readonly DependencyProperty FolderName =
            DependencyProperty.RegisterAttached("FolderName",
            typeof(string), typeof(FolderDialogBehavior));

    public static string GetFolderName(DependencyObject obj)
    {
        return (string)obj.GetValue(FolderName);
    }

    public static void SetFolderName(DependencyObject obj, string value)
    {
        obj.SetValue(FolderName, value);
    }
    #endregion

    private void OnClick(object sender, RoutedEventArgs e)
    {
        var dialog = new FolderBrowserDialog();
        var currentPath = GetValue(FolderName) as string;
        dialog.SelectedPath = currentPath;
        var result = dialog.ShowDialog();
        if (result == DialogResult.OK)
        {
            SetValue(FolderName, dialog.SelectedPath);
        }
    }
}
1 голос
/ 24 октября 2010

Только такой диалог FileDialog . Это часть WinForms, но на самом деле это единственная оболочка вокруг стандартного диалогового окна WinAPI. И я не думаю, что это уродливо, на самом деле это часть ОС, поэтому похоже, что ОС работает на ней.

В противном случае вам ничто не поможет. Вам либо нужно искать стороннюю реализацию, либо бесплатную (и я не думаю, что есть что-то хорошее), либо платную.

...