我希望用户选择一个目录,然后保存我将生成的文件。我知道在WPF中我应该使用Win32中的OpenFileDialog
,但遗憾的是对话框需要选择文件 - 如果我只是单击“确定”而不选择一个文件,它将保持打开状态。我可以通过让用户选择一个文件然后去除路径以找出它所属的目录来“破解”这个功能,但最好不直观。有没有人见过这个呢?
答案 0 :(得分:371)
您可以使用内置的FolderBrowserDialog类。不要介意它在System.Windows.Forms
名称空间中。
using (var dialog = new System.Windows.Forms.FolderBrowserDialog())
{
System.Windows.Forms.DialogResult result = dialog.ShowDialog();
}
如果您希望窗口在某个WPF窗口上是模态的,请参阅问题How to use a FolderBrowserDialog from a WPF application。
编辑:如果你想要一些比简单,丑陋的Windows Forms FolderBrowserDialog更有趣的东西,有一些替代方案可以让你使用Vista对话框:
using Microsoft.WindowsAPICodePack.Dialogs;
...
var dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
CommonFileDialogResult result = dialog.ShowDialog();
请注意,此对话框在Windows Vista之前的操作系统上不可用,因此请务必先检查CommonFileDialog.IsPlatformSupported
。
答案 1 :(得分:39)
我创建了一个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();
}
}
}
}
答案 2 :(得分:9)
答案 3 :(得分:7)
对于那些不想创建自定义对话框但仍然喜欢100%WPF方式并且不想使用单独的DDL,其他依赖项或过时的API的人,我想出了一个非常简单的hack使用Save作为对话。
不需要使用指令,您只需复制粘贴下面的代码即可!
它应该仍然非常人性化,大多数人都不会注意到。
这个想法来自于我们可以更改对话框的标题,隐藏文件以及轻松解决生成的文件名这一事实。
这肯定是一个很大的黑客,但也许它可以很好地满足您的使用......
在这个示例中,我有一个文本框对象来包含生成的路径,但如果您愿意,可以删除相关的行并使用返回值...
// 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;
}
这个黑客的唯一问题是:
大多数人都不会注意到这些,虽然我绝对更喜欢使用正式的WPF方式,如果微软会从他们的屁股中脱颖而出,但在他们这样做之前,那是我的临时解决方案。
答案 4 :(得分:6)
对于目录对话框以获取目录路径,首先添加引用System.Windows.Forms,然后单击Resolve,然后将此代码放在按钮单击中。
var dialog = new FolderBrowserDialog();
dialog.ShowDialog();
folderpathTB.Text = dialog.SelectedPath;
(folderpathTB是TextBox的名称,我将wana放在文件夹路径中,或者你也可以将它分配给字符串变量,例如。)
string folder = dialog.SelectedPath;
如果您获得FileName / path,只需在Button Click
上执行此操作 FileDialog fileDialog = new OpenFileDialog();
fileDialog.ShowDialog();
folderpathTB.Text = fileDialog.FileName;
(folderpathTB是TextBox的名称,我将wana放入文件路径,或者你也可以将它分配给字符串变量)
注意:对于文件夹对话框,必须将System.Windows.Forms.dll添加到项目中,否则它将无法正常工作。
答案 5 :(得分:6)
可以在Nuget找到Ookii文件夹对话框。
PM> Install-Package Ookii.Dialogs
并且,示例代码如下。
var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
if (dialog.ShowDialog(this).GetValueOrDefault())
{
textBoxFolderPath.Text = dialog.SelectedPath;
}
答案 6 :(得分:4)
实现您想要的最佳方法是创建自己的基于wpf的控件,或使用由其他人制作的控件
为什么?因为在wpf应用程序中使用winforms对话框时会出现明显的性能影响(由于某种原因)
我推荐这个项目
https://opendialog.codeplex.com/
或Nuget:
PM> Install-Package OpenDialog
它非常适合MVVM,它不会包装winforms对话框
答案 7 :(得分:4)
我在下面的链接中找到了以下代码......它有效 matrix multiplication
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
}
答案 8 :(得分: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
适用于文件,带过滤器的文件,文件夹等
答案 9 :(得分:2)
VistaFolderBrowserDialog
就是你想要的那个。如果您只需要Ooki Dialogs中的文件夹浏览器而不需要download the Source,请选择文件夹浏览器所需的文件(提示: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行中的代码是您可以使用的示例,但您需要从this,
中删除MessageBox.Show(this,
以获取WPF。
适用于我的机器[TM]
答案 10 :(得分:2)
我知道这是一个老问题,但是一个简单的方法是使用WPF提供的FileDialog选项并使用System.IO.Path.GetDirectory(filename)。
答案 11 :(得分:1)
这些答案都不适用于我(通常缺少参考或某些内容)
但这很简单:
Using FolderBrowserDialog in WPF application
添加对System.Windows.Forms
的引用并使用以下代码:
var dialog = new System.Windows.Forms.FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dialog.ShowDialog();
无需追踪丢失的包裹。或者添加大量的课程
这为我提供了一个现代文件夹选择器,它还允许您创建一个新文件夹
我还没有看到部署到其他机器时的影响
答案 12 :(得分: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;
}
答案 13 :(得分:0)
如先前答案所述,FolderBrowserDialog
是用于此目的的类。有些人对此对话框的外观和行为有(合理的)担忧。好消息是它was "modernized" in NET Core 3.0,因此对于那些编写针对该版本或更高版本的Windows Forms或WPF应用程序的人来说,现在是一个可行的选择(如果仍然使用NET Framework,您会很不幸)。
在.NET Core 3.0中,Windows Forms用户 [sic] 是Windows Vista中引入的更新的基于COM的控件:
对于reference System.Windows.Forms
in a NET Core WPF app,有必要编辑项目文件并添加以下行:
<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
属性似乎也被忽略,无论如何始终显示按钮。
答案 14 :(得分:0)
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();
}
}
}