选择文件夹对话框WPF


70

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

我的要求:

  • 能够查看标准文件夹树

  • 能够选择文件夹

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

据我了解,直到2010年(.Net 4.0)都不会出现标准的文件夹对话框,但4.0版可能会有一些更改?

还是剩下的就是使用老式的WinForms对话框?如果这是满足我需求的唯一方法,我如何使其更接近于Vista / 7风格而不是Win9x?

在某些论坛上,我看到了此类对话框的实现,但是在Windows 95上却带有旧的丑陋图标。它确实看起来不太好。


2
查看Sven Groot出色的WinForms和WPF的Ookii.Dialogs,它们为您提供了现代的“ Vista”样式的文件夹和文件对话框。
David Cuccia 2012年

我正在使用wxPython python模块github.com/wxWidgets/Phoenix
JinSnow

下面是一个更新的链接Ookii对话框进行WPF打靶.NET 4.5和有关的NuGet可
C.奥古斯托Proiete

Answers:


21

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

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

幸运的是,打开/保存对话框是围绕Win32 API的非常薄的包装程序,可以轻松地通过正确的标志调用以获取Vista / 7样式(设置清单后)


109

Pavel Yosifovich撰写的Windows Presentation Foundation 4.5 Cookbook在第155页的“使用公共对话框”部分中说:

“文件夹选择(而不是文件)呢?WPF OpenFileDialog不支持。一种解决方案是使用Windows Forms的FolderBrowseDialog类。另一种好的解决方案是使用简短介绍的Windows API代码包。”

我从Microsoft®.NET Framework的Windows®API代码包 下载了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
}

130
我不敢相信Microsoft不会默认在WPF中包含FolderBrowserDialog ...
贪睡

24
Windows API代码包可通过此处此处的Nuget获得。这对我来说很好。
华莱士·凯利

3
它对我来说很好。我也只写下面的命令,所以帖子有所有信息。通过VS中的程序包管理器控制台进行安装“ Install-Package Windows7APICodePack-Core”,“ Install-Package Windows7APICodePack-Shell”
Peter T.

我相信到此文件的链接已关闭。
alex

我试过了,但CommonOpenFileDialog没有被认可。(是的,我输入using了)。
Nick.McDermaid


11

如果您不想使用Windows窗体或编辑清单文件,我想出了一个非常简单的技巧,即使用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;
}

此骇客的唯一问题是:

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

大多数人不会注意到这些,尽管如果微软想让头脑冷静的话,我绝对会喜欢使用官方的WPF方法,但是在他们这样做之前,这是我的临时解决方案。


1
被低估的答案
艾哈迈德·穆罕默德'18

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


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的引用。


18
我认为关键是不能使用OpenFileDialog选择文件夹。
Neutrino

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

将此与@TPowers答案结合使用,效果很好。此外,对于“我”的命名空间..xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
bdeem


2

FolderBrowserDialog来自的班级System.Windows.Forms是显示一个对话框,允许用户选择一个文件夹中的推荐方法。

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

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

在.NET Core 3.0中,Windows Forms用户[sic] 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属性似乎也被忽略,无论如何总是显示该按钮。


1

只有这样的对话框才是FileDialog。它是WinForms的一部分,但实际上仅是WinAPI标准OS文件对话框的包装。而且我认为它并不丑陋,它实际上是OS的一部分,因此看起来像在运行OS一样。

否则,没有任何帮助。您要么需要免费(或者我认为没有任何好处)还是要付费的第三方实施方案。


谢谢!到目前为止,这是最好的答案。为MVVM或标准窗口编写代码非常简单。
Mark Bonafe

4
但是,这不允许您选择文件夹...问题的全部内容
Nick.McDermaid

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.