打开目录对话框

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

395083 次浏览

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

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

如果你想让窗口在某些WPF窗口上是模态的,请参阅问题如何从WPF应用程序中使用FolderBrowserDialog


编辑:如果你想要一些比普通的、丑陋的Windows窗体文件夹浏览器对话框更花哨的东西,有一些替代方案允许你使用Vista对话框:

  • 第三方库,例如Ookii对话框(。NET 4.5 +)

  • < p > Windows API代码包- shell:

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

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

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

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

Ookii dialog Select Folder截图 . sh . sh

https://github.com/ookii-dialogs

实现你想要的最好的方法是创建你自己的基于wpf的控件,或者使用别人做的控件 为什么?因为在WPF应用程序中使用winforms对话框(出于某种原因)
时将会有明显的性能影响 我推荐这个项目
https://opendialog.codeplex.com/ < br > 或Nuget:

PM> Install-Package OpenDialog

它是非常MVVM友好的,它没有包装winforms对话框

对于目录对话框获取目录路径,首先添加引用System.Windows。表单,然后解析,然后把这个代码放在按钮点击。

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

(folderpathTB是文本框的名字,我想把文件夹路径,或者你可以把它分配给一个字符串变量也就是)

    string folder = dialog.SelectedPath;

如果你想获得文件名/路径,只需在按钮单击上这样做

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

(folderpathTB是文本框的名字,我想把文件路径,或者你可以把它分配给一个字符串变量太)

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

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

我在下面的链接上找到了下面的代码…这个方法奏效了 选择文件夹对话框WPF < / p >

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
}

Ookii VistaFolderBrowserDialog是你想要的。

如果你只需要Ooki对话框中的文件夹浏览器,而不需要下载源代码中的其他任何文件,那么选择文件夹浏览器所需的文件(提示:7个文件),它在. net 4.5.2中构建良好。我必须添加System.Drawing的引用。将原项目中的参考资料与你的进行比较。

如何确定哪些文件?在不同的Visual Studio实例中打开你的应用程序和Ookii。将VistaFolderBrowserDialog.cs添加到应用程序中,并继续添加文件,直到构建错误消失。你在Ookii项目中找到依赖项-控制-单击你想要跟踪到它的源(双关语)。

如果你懒得这么做,这里有你需要的文件……

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中的代码是一个你可以使用的例子,但是你需要从WPF的MessageBox.Show(this,中删除this,

在我的机器上工作

我建议,在黄金套餐中加入:

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

适用于文件,文件过滤器,文件夹等

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

但这很简单:

在WPF应用程序中使用FolderBrowserDialog

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

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

没有必要去寻找丢失的包裹。或者添加大量的类

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

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

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

你可以在WPF中这样使用smth。我已经创建了示例方法。 检查下面。< / p >
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;
}

对于那些不想创建自定义对话框,但仍然喜欢100% WPF方式,不想使用单独的ddl,额外的依赖项或过时的api的人,我提出了一个非常简单的hack,使用另存为对话框。

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

它应该仍然是非常友好的,大多数人都不会注意到。

这个想法来自于这样一个事实,我们可以改变对话框的标题,隐藏文件,并很容易地处理产生的文件名。

这是一个大黑客肯定,但也许它会做的工作只是为了你的使用…

在这个例子中,我有一个文本框对象来包含结果路径,但是如果你愿意,你可以删除相关的行,并使用一个返回值…

// 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方式,如果微软能把他们的头从他们的屁股里拿出来,但在他们这样做之前,这是我的临时修复。

正如前面的回答中所述,FolderBrowserDialog是用于此的类。有些人(有理由)担心这个对话框的外观和行为。好消息是它是“modernized"NET Core 3.0,所以现在是一个可行的选择,无论是Windows窗体或WPF应用程序的目标版本或更高(如果你仍然使用NET框架,你就不走运了)。

在。net Core 3.0中,Windows窗体用户(原文如此)是Windows Vista中引入的一个新的基于com的控件: FolderBrowserDialog in NET Core 3.0

.

对于在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属性似乎也被忽略了,按钮总是被显示。

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

看来微软。Win32 . net库不支持选择文件夹(只支持文件),所以你在WPF中运气不好(截至2022年7月)。我觉得现在最好的选择是WPF: https://github.com/ookii-dialogs/ookii-dialogs-wpf的Ookii。它工作得很好,正如预期的那样,在WPF减去微软的支持。你可以把它作为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>