73

我开发了一个 WPF4 应用程序,在我的应用程序中,我需要让用户选择一个文件夹,应用程序将在其中存储一些东西(文件、生成的报告等)。

我的要求:

  • 能够查看标准文件夹树

  • 能够选择文件夹

  • WPF 的外观和感觉,这个对话框必须看起来像是为 Windows Vista/7 而不是 Windows 2000 甚至 Win9x 设计的现代应用程序的一部分。

据我了解,在 2010 年(.Net 4.0)之前不会有标准的文件夹对话框,但也许 4.0 版有一些变化?

或者剩下要做的就是使用老式的 WinForms 对话框?如果这是做我需要的唯一方法,我怎样才能让它更接近 Vista/7 风格而不是 Win9x?

在一些论坛上,我看到了这样的对话框的实现,但带有旧的丑陋图标,就像 Windows 95。它看起来真的不太好。

4

12 回答 12

112

Pavel Yosifovich 的Windows Presentation Foundation 4.5 Cookbook在第 155 页的“使用常用对话框”一节中说:

“文件夹选择(而不是文件)怎么样?WPF OpenFileDialog 不支持。一个解决方案是使用 Windows 窗体的 FolderBrowseDialog 类。另一个好的解决方案是使用稍后描述的 Windows API 代码包。”

我从适用于 Microsoft® .NE​​T Framework 的 Windows® API 代码包中下载了 API 代码包 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
}
于 2013-07-18T01:19:48.823 回答
21

我很久以前在我的博客上写过它,WPF 对通用文件对话框的支持真的很糟糕(或者至少是在 3.5 中,我没有在版本 4 中签入) - 但它很容易解决。

您需要将正确的清单添加到您的应用程序 - 这将为您提供现代风格的消息框和文件夹浏览器 (WinForms FolderBrowserDialog) 但不是 WPF 文件打开/保存对话框,这在这 3 个帖子中进行了描述(如果您不在乎关于解释,只希望解决方案直接转到第 3 个):

幸运的是,打开/保存对话框是围绕 Win32 API 的非常薄的包装器,很容易使用正确的标志调用以获得 Vista/7 样式(在设置清单之后)

于 2010-10-24T15:18:01.703 回答
18

Windows API Code Pack-Shell添加到您的项目中

using Microsoft.WindowsAPICodePack.Dialogs;

...

var dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
CommonFileDialogResult result = dialog.ShowDialog();
于 2016-07-23T13:53:33.113 回答
11

如果您不想使用 Windows 窗体也不想编辑清单文件,我想出了一个非常简单的技巧,使用 WPF 的 SaveAs 对话框来实际选择目录。

不需要 using 指令,您可以简单地复制粘贴下面的代码!

它应该仍然非常用户友好,大多数人永远不会注意到。

这个想法来自这样一个事实,即我们可以很容易地更改该对话框的标题、隐藏文件以及处理生成的文件名。

这肯定是一个很大的黑客,但也许它会为你的使用做的很好......

在此示例中,我有一个文本框对象来包含结果路径,但如果您愿意,您可以删除相关行并使用返回值...

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

此 hack 的唯一问题是:

  • 确认按钮仍然显示“保存”而不是“选择目录”之类的东西,但在像我这样的情况下,我“保存”目录选择,所以它仍然有效......
  • 输入字段仍然显示“文件名”而不是“目录名”,但我们可以说目录是一种文件......
  • 仍然有一个“另存为类型”下拉菜单,但它的值显示为“目录(* .this.directory)”,用户无法将其更改为其他内容,对我有用......

大多数人不会注意到这些,虽然我肯定更喜欢使用官方的 WPF 方式,如果微软会让他们的头脑清醒,但在他们这样做之前,这是我的临时修复。

于 2018-05-09T20:54:35.473 回答
6

FolderBrowserDialog类 fromSystem.Windows.Forms是显示允许用户选择文件夹的对话框的推荐方式。

直到最近,此对话框的外观和行为与其他文件系统对话框不一致,这也是人们不愿使用它的原因之一。

好消息是,它FolderBrowserDialog 在 NET Core 3.0 中已“现代化”,因此对于那些编写针对该版本或更高版本的 Windows 窗体或 WPF 应用程序的人来说,现在是一个可行的选择。

在 .NET Core 3.0 中,Windows 窗体用户[原​​文如此] Windows Vista 中引入的基于 COM 的较新控件: NET Core 3.0 中的 FolderBrowserDialog

在 NET Core WPF 应用程序中引用System.Windows.Forms,需要编辑项目文件并添加以下行:

<UseWindowsForms>true</UseWindowsForms>

这可以直接放在现有<UseWPF>元素之后。

那么这只是使用对话框的一个例子:

using System;
using System.Windows.Forms;

...

using var dialog = new FolderBrowserDialog
{
    Description = "Time to select a folder",
    UseDescriptionForTitle = true,
    SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
        + Path.DirectorySeparatorChar,
    ShowNewFolderButton = true
};

if (dialog.ShowDialog() == DialogResult.OK)
{
    ...
}

FolderBrowserDialog有一个RootFolder属性,据说是“设置浏览开始的根文件夹”,但无论我设置什么都没有任何区别;SelectedPath似乎是用于此目的的更好属性,但是尾随反斜杠是必需的。

此外,该ShowNewFolderButton属性似乎也被忽略了,无论如何总是显示按钮。

于 2020-12-08T14:02:17.697 回答
5

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

于 2014-04-02T16:45:52.690 回答
4

Microsoft.Win32.OpenFileDialog 是 Windows 上任何应用程序使用的标准对话框。当您在 .NET 4.0 中使用 WPF 时,您的用户不会对其外观感到惊讶

该对话框在 Vista 中已更改。.NET 3.0 和 3.5 中的 WPF 仍使用旧版对话框,但已在 .NET 4.0 中修复。我只能猜测您启动此线程是因为您看到了那个旧对话框。这可能意味着您实际上正在运行一个针对 3.5 的程序。是的,Winforms 包装器确实得到了升级并显示了 Vista 版本。System.Windows.Forms.OpenFileDialog 类,您需要添加对 System.Windows.Forms 的引用。

于 2010-10-24T11:43:58.190 回答
3

根据 Oyun 的回答,最好使用 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);
        }
    }
}
于 2015-03-09T15:13:41.997 回答
3

WPF的Ookii 对话框有一个VistaFolderBrowserDialog类,它提供了 WPF 文件夹浏览器对话框的完整实现。

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

Ookii 文件夹浏览器对话框

还有一个适用于Windows Forms的版本。

于 2018-10-04T03:20:43.493 回答
1

只有这样的对话框是FileDialog。它是 WinForms 的一部分,但实际上它只是 WinAPI 标准 OS 文件对话框的包装器。而且我认为它并不难看,它实际上是操作系统的一部分,所以它看起来就像运行它的操作系统。

否则,没有什么可以帮助您的。您要么需要寻找第 3 方实施,要么是免费的(我认为没有任何好处),要么是付费的。

于 2010-10-24T11:44:28.113 回答
0

C. Augusto Proiete 对原始问题的评论建议使用 Ookii 对话 ( https://github.com/ookii-dialogs/ookii-dialogs-wpf )。这就是我最终在我的情况下使用的。这是我在我的应用程序中使用它的方式。

var dialog = new VistaFolderBrowserDialog()
{
    Description = "Select Folder",
    RootFolder = Environment.SpecialFolder.Desktop,
    ShowNewFolderButton = true,
    UseDescriptionForTitle = true
};

var result = dialog.ShowDialog();

if (result.HasValue && result.Value)
{
    _mySelectedFolder = dialog.SelectedPath;
}
于 2021-04-01T01:50:21.593 回答
0

只是说一件事,WindowsAPICodePack不能CommonOpenFileDialog在Windows 7 6.1.7600上打开。

于 2020-10-28T07:00:42.897 回答