I develop a WPF4 application and in my app I need to let the user select a folder where the application will store something (files, generated reports etc.).
My requirements:
Ability to see the standard folder tree
Ability to select a folder
WPF look & feel, this dialog must look like part of a modern application designed for Windows Vista/7 and not Windows 2000 or even Win9x.
As I understand, until 2010 (.Net 4.0) there won't be a standard folder dialog, but maybe there are some changes in version 4.0?
Or all what rest to do is use old-school WinForms dialog? If it's the only way to do what I need, how can I make it closer to Vista/7 style and not Win9x?
On some forums, I saw the implementation of such dialogs but with old ugly icons à la Windows 95. It really doesn't look nice.
This question is related to
c#
.net
wpf
folderbrowserdialog
MVVM + WinForms FolderBrowserDialog as behavior
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);
}
}
}
Usage
<Button Grid.Column="3" Content="...">
<Interactivity:Interaction.Behaviors>
<Behavior:FolderDialogBehavior SetterName="SomeFolderPathPropertyName"/>
</Interactivity:Interaction.Behaviors>
</Button>
Blogpost: http://kostylizm.blogspot.ru/2014/03/wpf-mvvm-and-winforms-folder-dialog-how.html
Based on Oyun's answer, it's better to use a dependency property for the FolderName. This allows (for example) binding to sub-properties, which doesn't work in the original. Also, in my adjusted version, the dialog shows selects the initial folder.
Usage in XAML:
<Button Content="...">
<i:Interaction.Behaviors>
<Behavior:FolderDialogBehavior FolderName="{Binding FolderPathPropertyName, Mode=TwoWay}"/>
</i:Interaction.Behaviors>
</Button>
Code:
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);
}
}
}
Just to say one thing, WindowsAPICodePack
can not open CommonOpenFileDialog
on Windows 7 6.1.7600.
If you don't want to use Windows Forms nor edit manifest files, I came up with a very simple hack using WPF's SaveAs dialog for actually selecting a directory.
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 :
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.
Only such dialog is FileDialog. Its part of WinForms, but its actually only wrapper around WinAPI standard OS file dialog. And I don't think it is ugly, its actually part of OS, so it looks like OS it is run on.
Other way, there is nothing to help you with. You either need to look for 3rd party implementation, either free (and I don't think there are any good) or paid.
Windows Presentation Foundation 4.5 Cookbook by Pavel Yosifovich on page 155 in the section on "Using the common dialog boxes" says:
"What about folder selection (instead of files)? The WPF OpenFileDialog does not support that. One solution is to use Windows Forms' FolderBrowseDialog class. Another good solution is to use the Windows API Code Pack described shortly."
I downloaded the API Code Pack from Windows® API Code Pack for Microsoft® .NET Framework Windows API Code Pack: Where is it?, then added references to Microsoft.WindowsAPICodePack.dll and Microsoft.WindowsAPICodePack.Shell.dll to my WPF 4.5 project.
Example:
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
}
Add The Windows API Code Pack-Shell to your project
using Microsoft.WindowsAPICodePack.Dialogs;
...
var dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
CommonFileDialogResult result = dialog.ShowDialog();
The Ookii Dialogs for WPF has a VistaFolderBrowserDialog
class that provides a complete implementation of a folder browser dialog for WPF.
There's also a version that works with Windows Forms.
Microsoft.Win32.OpenFileDialog is the standard dialog that any application on Windows uses. Your user won't be surprised by its appearance when you use WPF in .NET 4.0
The dialog was altered in Vista. WPF in .NET 3.0 and 3.5 still used the legacy dialog but that was fixed in .NET 4.0. I can only guess that you started this thread because you are seeing that old dialog. Which probably means you're actually running a program that is targeting 3.5. Yes, the Winforms wrapper did get the upgrade and shows the Vista version. System.Windows.Forms.OpenFileDialog class, you'll need to add a reference to System.Windows.Forms.
The FolderBrowserDialog
class from System.Windows.Forms
is the recommended way to display a dialog that allows a user to select a folder.
Until recently, the appearance and behaviour of this dialog was not in keeping with the other filesystem dialogs, which is one of the reasons why people were reluctant to use it.
The good news is that FolderBrowserDialog
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.
In .NET Core 3.0, Windows Forms users [sic] a newer COM-based control that was introduced in Windows Vista:
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.
Source: Stackoverflow.com