打开目录对话框

发布于 2024-08-15 04:12:49 字数 192 浏览 1 评论 0原文

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

I want the user to select a directory where a file that I will then generate will be saved. I know that in WPF I should use the OpenFileDialog from Win32, but unfortunately the dialog requires file(s) to be selected - it stays open if I simply click OK without choosing one. I could "hack up" the functionality by letting the user pick a file and then strip the path to figure out which directory it belongs to but that's unintuitive at best. Has anyone seen this done before?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(19

无人问我粥可暖 2024-08-22 04:12:49

2023 年更新:最后,通过 .NET 8,WPF 获得了原生、现代的OpenFolderDialog

var folderDialog = new OpenFolderDialog
{
    // Set options here
};

if (folderDialog.ShowDialog() == true)
{
    var folderName = folderDialog.FolderName;
    // Do something with the result
}

这是否意味着 Microsoft 最终投入资源向 WPF 添加缺失的功能?当然不是! Microsoft 员工正忙于帮助您构建云原生基于 AI 的<在此插入更多流行语>Teams 聊天机器人。像修复 WPF 来解决现实、无聊的业务需求这样的平凡任务留给了社区志愿者,例如 Jan,谁将此文件夹浏览器对话框添加到 .NET


.NET Framwork 4.8 的旧答案

您可以使用内置的 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 4.5+)

  • Windows API 代码包外壳

     使用 Microsoft.WindowsAPICodePack.Dialogs;
    
      ...
    
      var 对话框 = new CommonOpenFileDialog();
      对话框.IsFolderPicker = true;
      CommonFileDialogResult 结果=dialog.ShowDialog();
    

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

UPDATE 2023: Finally, with .NET 8, WPF gets a native, modern OpenFolderDialog:

var folderDialog = new OpenFolderDialog
{
    // Set options here
};

if (folderDialog.ShowDialog() == true)
{
    var folderName = folderDialog.FolderName;
    // Do something with the result
}

Does this mean that Microsoft finally invests resources in adding missing functionality to WPF? Of course not! Microsoft employees are busy enabling you to build cloud-native AI-based <insert more buzzwords here> Teams chat bots. Mundane tasks like fixing WPF to solve real-live, boring business needs are left to community volunteers like Jan, who added this folder browser dialog to .NET.


Old answer for .NET Framwork 4.8:

You can use the built-in FolderBrowserDialog class for this. Don't mind that it's in the System.Windows.Forms namespace.

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

If you want the window to be modal over some WPF window, see the question How to use a FolderBrowserDialog from a WPF application.


EDIT: If you want something a bit more fancy than the plain, ugly Windows Forms FolderBrowserDialog, there are some alternatives that allow you to use the Vista dialog instead:

  • Third-party libraries, such as Ookii dialogs (.NET 4.5+)

  • The Windows API Code Pack-Shell:

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

    Note that this dialog is not available on operating systems older than Windows Vista, so be sure to check CommonFileDialog.IsPlatformSupported first.

嗳卜坏 2024-08-22 04:12:49

我创建了一个 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();
            }
        }
    }
 }

I created a UserControl which is used like this:

  <UtilitiesWPF:FolderEntry Text="{Binding Path=LogFolder}" Description="Folder for log files"/>

The xaml source looks like this:

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

and the code-behind

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();
            }
        }
    }
 }
寂寞美少年 2024-08-22 04:12:49

正如前面的答案中所述,FolderBrowserDialog 是用于此目的的类。有些人对此对话框的外观和行为有(合理的)担忧。好消息是它已“现代化” “在 NET Core 3.0 中,对于那些编写针对该版本或更高版本的 Windows 窗体或 WPF 应用程序的人来说,现在是一个可行的选择(如果仍然使用 NET Framework,那么你就不走运了)。

在 .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 属性似乎也被忽略,无论如何,该按钮始终显示。

As stated in earlier answers, FolderBrowserDialog is the class to use for this. Some people have (justifiable) concerns with the appearance and behaviour of this dialog. The good news is that it was "modernized" in NET Core 3.0, so is now a viable option for those writing either Windows Forms or WPF apps targeting that version or later (you're out of luck if still using NET Framework though).

In .NET Core 3.0, Windows Forms users [sic] a newer COM-based control that was introduced in Windows Vista:
FolderBrowserDialog in NET Core 3.0

To reference System.Windows.Forms in a NET Core WPF app, it is necessary to edit the project file and add the following line:

<UseWindowsForms>true</UseWindowsForms>

This can be placed directly after the existing <UseWPF> element.

Then it's just a case of using the dialog:

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 has a RootFolder property that supposedly "sets the root folder where the browsing starts from" but whatever I set this to it didn't make any difference; SelectedPath seemed to be the better property to use for this purpose, however the trailing backslash is required.

Also, the ShowNewFolderButton property seems to be ignored as well, the button is always shown regardless.

尾戒 2024-08-22 04:12:49

Ookii 文件夹对话框可以在 Nuget 中找到。

PM> Install-Package Ookii.Dialogs.Wpf

并且,示例代码如下。

var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
if (dialog.ShowDialog(this).GetValueOrDefault())
{
    textBoxFolderPath.Text = dialog.SelectedPath;
}

有关如何使用它的更多信息:https://github.com/augustoproiete/ookii-dialogs-wpf

Ookii folder dialog can be found at Nuget.

PM> Install-Package Ookii.Dialogs.Wpf

And, example code is as below.

var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
if (dialog.ShowDialog(this).GetValueOrDefault())
{
    textBoxFolderPath.Text = dialog.SelectedPath;
}

More information on how to use it: https://github.com/augustoproiete/ookii-dialogs-wpf

指尖上的星空 2024-08-22 04:12:49

对于那些不想创建自定义对话框但仍然喜欢 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 方式,但在他们这样做之前,这就是我的临时解决办法。

For those who don't want to create a custom dialog but still prefer a 100% WPF way and don't want to use separate DDLs, additional dependencies or outdated APIs, I came up with a very simple hack using the Save As dialog.

No using directive needed, you may simply copy-paste the code below !

It should still be very user-friendly and most people will never notice.

The idea comes from the fact that we can change the title of that dialog, hide files, and work around the resulting filename quite easily.

It is a big hack for sure, but maybe it will do the job just fine for your usage...

In this example I have a textbox object to contain the resulting path, but you may remove the related lines and use a return value if you wish...

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

The only issues with this hack are :

  • Acknowledge button still says "Save" instead of something like "Select directory", but in a case like mines I "Save" the directory selection so it still works...
  • Input field still says "File name" instead of "Directory name", but we can say that a directory is a type of file...
  • There is still a "Save as type" dropdown, but its value says "Directory (*.this.directory)", and the user cannot change it for something else, works for me...

Most people won't notice these, although I would definitely prefer using an official WPF way if microsoft would get their heads out of their asses, but until they do, that's my temporary fix.

缘字诀 2024-08-22 04:12:49

Ookii 对话框 包含一个用于选择文件夹(而不是文件)的对话框:

Ookii 对话框选择文件夹屏幕截图

https://github.com/ookii-dialogs

Ookii Dialogs includes a dialog for selecting a folder (instead of a file):

Ookii Dialogs Select Folder Screenshot

https://github.com/ookii-dialogs

峩卟喜欢 2024-08-22 04:12:49

对于要获取目录路径的目录对话框,首先添加引用 System.Windows.Forms,然后解析,然后将此代码放在单击按钮中。

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

(folderpathTB 是我想要放置文件夹路径的 TextBox 的名称,或者您也可以将其分配给字符串变量,即)

    string folder = dialog.SelectedPath;

如果您想要获取文件名/路径,只需在按钮单击上执行此操作

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

(folderpathTB 是我想要的 TextBox 的名称)输入文件路径,或者也可以将其分配给字符串变量)

注意:对于文件夹对话框,必须将System.Windows.Forms.dll添加到项目中,否则将无法工作。

For Directory Dialog to get the Directory Path, First Add reference System.Windows.Forms, and then Resolve, and then put this code in a button click.

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

(folderpathTB is name of TextBox where I wana put the folder path, OR u can assign it to a string variable too i.e.)

    string folder = dialog.SelectedPath;

And if you wana get FileName/path, Simply do this on Button Click

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

(folderpathTB is name of TextBox where I wana put the file path, OR u can assign it to a string variable too)

Note: For Folder Dialog, the System.Windows.Forms.dll must be added to the project, otherwise it wouldn't work.

路还长,别太狂 2024-08-22 04:12:49

我在下面的链接中找到了下面的代码...并且它有效
选择文件夹对话框 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
}

I found the below code on below link... and it worked
Select folder dialog 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
}
反差帅 2024-08-22 04:12:49

我建议,在nugget包中添加:

  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

适用于文件、带过滤器的文件、文件夹等

I'd suggest, to add in the nugget package:

  Install-Package OpenDialog

Then the way to used it is:

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

Here's the documentation:
http://opendialog.codeplex.com/documentation

Works for Files, files with filter, folders, etc

原野 2024-08-22 04:12:49

实现您想要的效果的最佳方法是创建您自己的基于 wpf 的控件,或使用其他人制作的控件
为什么 ?因为在 wpf 应用程序中使用 winforms 对话框时会对性能产生明显的影响(出于某种原因)
我推荐这个项目
https://opendialog.codeplex.com/
或 Nuget :

PM> Install-Package OpenDialog

它对 MVVM 非常友好,并且不会包装 winforms 对话框

The best way to achieve what you want is to create your own wpf based control , or use a one that was made by other people
why ? because there will be a noticeable performance impact when using the winforms dialog in a wpf application (for some reason)
i recommend this project
https://opendialog.codeplex.com/
or Nuget :

PM> Install-Package OpenDialog

it's very MVVM friendly and it isn't wraping the winforms dialog

耶耶耶 2024-08-22 04:12:49

Ookii VistaFolderBrowserDialog 就是您想要的。

如果您只需要 Ooki 对话框 中的文件夹浏览器,而不需要其他内容,则 下载源代码,挑选文件夹浏览器所需的文件(提示: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

throw new InvalidOperationException(Properties.Resources.FolderBrowserDialogNoRootFolder);

throw new InvalidOperationException("Unable to retrieve the root folder.");

根据其 license.txt

中的代码将其版权声明添加到您的应用程序 \Ookii.Dialogs.Wpf.Sample 中\MainWindow.xaml.cs 第 160-169 行是一个可以使用的示例,但您需要从 MessageBox.Show(this, 中删除 this, WPF

适用于我的机器 [TM] 。

The Ookii VistaFolderBrowserDialog is the one you want.

If you only want the Folder Browser from Ooki Dialogs and nothing else then download the Source, cherry-pick the files you need for the Folder browser (hint: 7 files) and it builds fine in .NET 4.5.2. I had to add a reference to System.Drawing. Compare the references in the original project to yours.

How do you figure out which files? Open your app and Ookii in different Visual Studio instances. Add VistaFolderBrowserDialog.cs to your app and keep adding files until the build errors go away. You find the dependencies in the Ookii project - Control-Click the one you want to follow back to its source (pun intended).

Here are the files you need if you're too lazy to do that ...

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

Edit line 197 in VistaFolderBrowserDialog.cs unless you want to include their Resources.Resx

throw new InvalidOperationException(Properties.Resources.FolderBrowserDialogNoRootFolder);

throw new InvalidOperationException("Unable to retrieve the root folder.");

Add their copyright notice to your app as per their license.txt

The code in \Ookii.Dialogs.Wpf.Sample\MainWindow.xaml.cs line 160-169 is an example you can use but you will need to remove this, from MessageBox.Show(this, for WPF.

Works on My Machine [TM]

神也荒唐 2024-08-22 04:12:49

这些答案都不适合我(通常缺少参考或类似的东西)

但这很简单:

在WPF应用程序中使用FolderBrowserDialog

添加对System.Windows.Forms的引用并使用此代码:

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

无需追踪丢失的包。或者添加大量的类

这给了我一个现代的文件夹选择器,它还允许您创建一个新文件夹

我还没有看到部署到其他机器时的影响

None of these answers worked for me (generally there was a missing reference or something along those lines)

But this quite simply did:

Using FolderBrowserDialog in WPF application

Add a reference to System.Windows.Forms and use this code:

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

No need to track down missing packages. Or add enormous classes

This gives me a modern folder selector that also allows you to create a new folder

I'm yet to see the impact when deployed to other machines

ˇ宁静的妩媚 2024-08-22 04:12:49

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

I know this is an old question, but a simple way to do this is use the FileDialog option provided by WPF and using System.IO.Path.GetDirectory(filename).

情何以堪。 2024-08-22 04:12:49

Microsoft.Win32 .NET 库似乎不支持选择文件夹(仅支持文件),因此您在 WPF 中运气不好(截至 7/2022)。我觉得现在最好的选择是 Ookii for WPF: https://github.com/ookii -dialogs/ookii-dialogs-wpf。它在 WPF 中运行良好并且符合预期,但没有 Microsoft 支持。您可以将其作为 NuGet 包获取。 XAML 视图背后的代码:

public partial class ExportRegionView : UserControl
{
    public ExportRegionView()
    {
        InitializeComponent();
    }
    private void SavePath(object sender, RoutedEventArgs e)
    {
        var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
        dialog.Description = "SIPAS Export Folder";
        dialog.UseDescriptionForTitle = true;
        if (dialog.ShowDialog().GetValueOrDefault())
        {
            ExportPath.Text = dialog.SelectedPath;
        }
    }
}

XAML: <Button Grid.Row="1" Grid.Column="3" Style="{DynamicResource Esri_Button}" Click="SavePath" Margin="5,5,5,5">Path</Button>

It seems that the Microsoft.Win32 .NET library does not support selecting folders (only files), so you are out of luck in WPF (as of 7/2022). I feel the best option now is Ookii for WPF: https://github.com/ookii-dialogs/ookii-dialogs-wpf. It works great and as expected in WPF minus Microsoft support. You can get it as a NuGet package. Code behind XAML View:

public partial class ExportRegionView : UserControl
{
    public ExportRegionView()
    {
        InitializeComponent();
    }
    private void SavePath(object sender, RoutedEventArgs e)
    {
        var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
        dialog.Description = "SIPAS Export Folder";
        dialog.UseDescriptionForTitle = true;
        if (dialog.ShowDialog().GetValueOrDefault())
        {
            ExportPath.Text = dialog.SelectedPath;
        }
    }
}

XAML: <Button Grid.Row="1" Grid.Column="3" Style="{DynamicResource Esri_Button}" Click="SavePath" Margin="5,5,5,5">Path</Button>
不奢求什么 2024-08-22 04:12:49

你可以在 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;           
       }

You could use smth like this in WPF. I've created example method.
Check below.

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;           
       }
夜夜流光相皎洁 2024-08-22 04:12:49

最新的 .NET 8 有特殊的 OpenFolderDialog - 您可以使用它!

Latest .NET 8 got special OpenFolderDialog - you can use it!

白鸥掠海 2024-08-22 04:12:49

这是一个简单得多的答案。 WPF 使用 Microsoft.Win32 中的 OpenFolderDialag

using Microsoft.Win32;

 public void ExportCSV_Click(object sender, RoutedEventArgs e)
 {
      var dialog = new OpenFolderDialog();

      if (dialog.ShowDialog() == true)
      {
          string filePath = dialog.FolderName;
      }
 }

This is much simpler answer. WPF is using OpenFolderDialag from Microsoft.Win32

using Microsoft.Win32;

 public void ExportCSV_Click(object sender, RoutedEventArgs e)
 {
      var dialog = new OpenFolderDialog();

      if (dialog.ShowDialog() == true)
      {
          string filePath = dialog.FolderName;
      }
 }
翻身的咸鱼 2024-08-22 04:12:49
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Gearplay
{
    /// <summary>
    /// Логика взаимодействия для OpenFolderBrows.xaml
    /// </summary>
    public partial class OpenFolderBrows : Page
    {
        internal string SelectedFolderPath { get; set; }
        public OpenFolderBrows()
        {
            InitializeComponent();
            Selectedpath();
            InputLogicalPathCollection();
             
        }

        internal void Selectedpath()
        {
            Browser.Navigate(@"C:\");
            
            Browser.Navigated += Browser_Navigated;
        }

        private void Browser_Navigated(object sender, NavigationEventArgs e)
        {
            SelectedFolderPath = e.Uri.AbsolutePath.ToString();
            //MessageBox.Show(SelectedFolderPath);
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
          
           
        }
        
        string [] testing { get; set; }
        private void InputLogicalPathCollection()
        {            // add Menu items for Cotrol 
            string[] DirectoryCollection_Path = Environment.GetLogicalDrives(); // Get Local Drives
            testing = new string[DirectoryCollection_Path.Length];
            //MessageBox.Show(DirectoryCollection_Path[0].ToString());
            MenuItem[]  menuItems = new MenuItem[DirectoryCollection_Path.Length]; // Create Empty Collection
            for(int i=0;i<menuItems.Length;i++)
            {
                // Create collection depend how much logical drives 
                menuItems[i] = new MenuItem();
                menuItems[i].Header = DirectoryCollection_Path[i];
                menuItems[i].Name = DirectoryCollection_Path[i].Substring(0,DirectoryCollection_Path.Length-1);
                DirectoryCollection.Items.Add(menuItems[i]);
                menuItems[i].Click += OpenFolderBrows_Click;
                testing[i]= DirectoryCollection_Path[i].Substring(0, DirectoryCollection_Path.Length - 1);
            }

            

        }
        
        private void OpenFolderBrows_Click(object sender, RoutedEventArgs e)
        {

            foreach (string str in testing)
            {
                if (e.OriginalSource.ToString().Contains("Header:"+str)) // Navigate to Local drive
                {
                    Browser.Navigate(str + @":\");
                   
                }


            }


        }

        private void Goback_Click(object sender, RoutedEventArgs e)
        {// Go Back
            try
            {
                Browser.GoBack();
            }catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Goforward_Click(object sender, RoutedEventArgs e)
        { //Go Forward
            try
            {
                Browser.GoForward();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        private void FolderForSave_Click(object sender, RoutedEventArgs e)
        {
            // Separate Click For Go Back same As Close App With send string var to Main Window ( Main class etc.) 
            this.NavigationService.GoBack();
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Gearplay
{
    /// <summary>
    /// Логика взаимодействия для OpenFolderBrows.xaml
    /// </summary>
    public partial class OpenFolderBrows : Page
    {
        internal string SelectedFolderPath { get; set; }
        public OpenFolderBrows()
        {
            InitializeComponent();
            Selectedpath();
            InputLogicalPathCollection();
             
        }

        internal void Selectedpath()
        {
            Browser.Navigate(@"C:\");
            
            Browser.Navigated += Browser_Navigated;
        }

        private void Browser_Navigated(object sender, NavigationEventArgs e)
        {
            SelectedFolderPath = e.Uri.AbsolutePath.ToString();
            //MessageBox.Show(SelectedFolderPath);
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
          
           
        }
        
        string [] testing { get; set; }
        private void InputLogicalPathCollection()
        {            // add Menu items for Cotrol 
            string[] DirectoryCollection_Path = Environment.GetLogicalDrives(); // Get Local Drives
            testing = new string[DirectoryCollection_Path.Length];
            //MessageBox.Show(DirectoryCollection_Path[0].ToString());
            MenuItem[]  menuItems = new MenuItem[DirectoryCollection_Path.Length]; // Create Empty Collection
            for(int i=0;i<menuItems.Length;i++)
            {
                // Create collection depend how much logical drives 
                menuItems[i] = new MenuItem();
                menuItems[i].Header = DirectoryCollection_Path[i];
                menuItems[i].Name = DirectoryCollection_Path[i].Substring(0,DirectoryCollection_Path.Length-1);
                DirectoryCollection.Items.Add(menuItems[i]);
                menuItems[i].Click += OpenFolderBrows_Click;
                testing[i]= DirectoryCollection_Path[i].Substring(0, DirectoryCollection_Path.Length - 1);
            }

            

        }
        
        private void OpenFolderBrows_Click(object sender, RoutedEventArgs e)
        {

            foreach (string str in testing)
            {
                if (e.OriginalSource.ToString().Contains("Header:"+str)) // Navigate to Local drive
                {
                    Browser.Navigate(str + @":\");
                   
                }


            }


        }

        private void Goback_Click(object sender, RoutedEventArgs e)
        {// Go Back
            try
            {
                Browser.GoBack();
            }catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Goforward_Click(object sender, RoutedEventArgs e)
        { //Go Forward
            try
            {
                Browser.GoForward();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        private void FolderForSave_Click(object sender, RoutedEventArgs e)
        {
            // Separate Click For Go Back same As Close App With send string var to Main Window ( Main class etc.) 
            this.NavigationService.GoBack();
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文