打开目录对话框


274

我希望用户选择一个目录,将在该目录中保存随后将生成的文件。我知道在WPF中我应该使用OpenFileDialogWin32中的from,但是不幸的是,该对话框要求选择文件-如果我只单击OK而不选择其中一个,它将保持打开状态。我可以通过让用户选择一个文件然后剥离路径以找出该文件属于哪个目录来“破解”该功能,但这充其量是不直观的。有人看过吗?




Answers:


406

您可以为此使用内置的FolderBrowserDialog类。不要介意它在System.Windows.Forms名称空间中。

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

如果希望该窗口在某些WPF窗口上具有模式,请参阅问题如何从WPF应用程序中使用FolderBrowserDialog


编辑:如果您要比普通的,丑陋的Windows窗体FolderBrowserDialog多花哨的东西,可以使用一些替代方法来使用Vista对话框:

  • 第三方库,例如Ookii对话框(.NET 3.5)
  • Windows API的代码包壳牌

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

    请注意,此对话框在Windows Vista之前的操作系统上不可用,因此请务必先检查CommonFileDialog.IsPlatformSupported


78
请注意,这是一个可怕的对话框。您无法将路径复制并粘贴到其中,并且它不支持“收藏夹”文件夹。总的来说,我给它5分中的0分,并建议任何人都不要使用它。除非Windows Vista出现了更好的文件夹对话框,否则没有合理的选择。有好的免费库在Vista +上显示出良好的对话框,而在XP上则显示出不良的对话框。
罗曼·斯塔科夫

70
不过,为什么WPF提供了一个很棒的OpenFileDialog而没有OpenFolderDialog?有点奇怪吗?为什么WPF不在这里?是否有计划在WPF中为此对话框添加类?
Paul-Sebastian Manole

14
不要忘记FolderBrowserDialog是一次性的。
LosManos 2014年

9
请注意,为了使用CommonOpenFileDialogfrom,WindowsAPICodePack您需要Install-Package WindowsAPICodePack-Shell。答案中提供的链接未列出该链接。
Nikola Novak 2014年

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?依赖项属性中的更改通知是否应该自动进行?
亨氏2009年

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的名称,或者u也可以将其分配给字符串变量,例如)

    string folder = dialog.SelectedPath;

如果要获取文件名/路径,只需在按钮上单击即可

    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的控件,或使用别人制作的控件,
为什么?因为在wpf应用程序中使用winforms对话框时(由于某些原因)会显着影响性能,所以
我建议您使用
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。将原始项目中的引用与您的引用进行比较。

您如何找出哪些文件?在不同的Visual Studio实例中打开您的应用程序和Ookii。添加VistaFolderBrowserDialog.cs到您的应用程序并继续添加文件,直到构建错误消失。您可以在Ookii项目中找到依赖项-按住Control键并单击要跟踪的依赖项,再回到其源代码(双关语)。

如果您懒得执行以下操作,则需要这些文件...

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

VistaFolderBrowserDialog.cs除非要包括它们的行,否则编辑第197行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

我知道这是一个古老的问题,但是执行此操作的一种简单方法是使用WPF提供的FileDialog选项并使用System.IO.Path.GetDirectory(filename)。


但是,即使告诉用户选择文件夹,用户也必须选择文件。经验不足的用户可能会在此时致电HelpDesk,询问为什么他必须选择文件夹时为什么必须选择文件
chriszo111 '18

0

这些答案都不适合我(通常缺少参考文献或类似内容)

但这很简单:

在WPF应用程序中使用FolderBrowserDialog

添加引用System.Windows.Forms并使用以下代码:

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

无需跟踪丢失的软件包。或添加大量课程

这为我提供了一个现代的文件夹选择器,该选择器还允许您创建一个新文件夹

我尚未看到部署到其他计算机时的影响


0

您可以在WPF中像这样使用smth。我创建了示例方法。检查下面。

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