I came up with a hack to get a folder browser in WPF, since Microsoft decided it was no worth adding it to WPF. No third party libraries are involved in this one.
I also found a work around to use it for MVVM situations.
To get the (hacked) folder browser, I employed the SaveFileDialog
I added the following imports
using System.IO;
using Microsoft.Win32;
Then I created a method to Get Folder Path
public string GetFolderPath()
{
SaveFileDialog folderDialog = new SaveFileDialog
{
AddExtension = false,
Title = "Select a Directory",
Filter = "All|*.*",
InitialDirectory = Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments),
CheckFileExists = false,
CheckPathExists = true,
FileName = Path.GetFileName("Select a folder"),
};
// Return null if the user does not click the OK button of the dialog displayed.
if (folderDialog.ShowDialog() != true)
{
return null;
}
// User clicked OK, get the full path of the predefined file name provided.
string path = folderDialog.FileName;
// Get the parent directory of the dummy/predefined file name supplied.
path = Directory.GetParent(path).FullName;
// If user changes or delete the directory, re-create it.
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
// return the folder path.
return path;
}
It worked pretty well for my simple projects. But my newest project followed strict MVVM pattern so View, Model, and View Model were grouped into separate projects:
MyApp.View
MyApp.Core
MyApp.ViewModel
Each Core and ViewModel projects were both using the
.NET Standard
Library, which does not have the
Microsoft.Win32
library. So I had to find a way to get file browser and the (hacked) folder browser into the view model project.
In order to use the FileDialog
and the hacked FolderBroser
, I
Created an Interface in the Core project which was a shared library in both the View and ViewModel projects
/// <summary>
/// Interface for handling file dialog results
/// </summary>
public interface IDialogResults
{
/// <summary>
/// Opens a file dialog for user to select files
/// </summary>
/// <returns></returns>
string GetFilePath();
/// <summary>
/// Opens a folder dialog box for user to select folders
/// </summary>
/// <returns></returns>
string GetFolderPath();
}
Then inherited it in the user control's partial class
public partial class FolderDialogUserControl : IDialogResults
which implemented the methods of the interface.
#region Implementation of IDialogResults
/// <inheritdoc />
public string GetFilePath()
{
OpenFileDialog fileDialog = new OpenFileDialog()
{
AddExtension = true,
CheckFileExists = true,
CheckPathExists = true,
Filter = "All|*.*",
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
};
if (!fileDialog.ShowDialog().HasValue)
{
return null;
}
// return the full path of the file selected.
return fileDialog.FileName;
}
/// <inheritdoc />
public string GetFolderPath()
{
SaveFileDialog folderDialog = new SaveFileDialog
{
AddExtension = false,
Title = "Select a Directory",
Filter = "Database File|*.ldf;*.mdf", // Prevents display of other file types
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
CheckFileExists = false,
CheckPathExists = true,
};
// Return null if the user does not click the OK button of the dialog displayed.
if (folderDialog.ShowDialog() != true)
{
return null;
}
// User clicked OK, get the full path of the predefined file name provided.
string path = folderDialog.FileName;
// Get the parent directory of the dummy/predefined file name supplied.
path = Directory.GetParent(path).FullName;
// If user changes or delete the directory, re-create it.
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
// return the folder path.
return path;
}
#endregion
Then in the DialogUserControl.xaml
file I created the button to initiate the folder open command. In the button properties,I added the command binding to the ICommand Property from the DialogUserControlViewModel; then I added the DialogUserControl itself as CommandParameter
Command="{Binding OpenFolderDialog}"
CommandParameter="{Binding ElementName=DialogUserControl}"
Then in the DialogUser ViewModel, I added the following code
/// <summary>
/// Opens a folder dialog for user to select a destination
/// </summary>
/// <param name="parameter">FolderDialogUserControl.xaml.cs</param>
private void BrowseFolderDialog(object parameter)
{
BackupDestination = (parameter as IDialogResults)?.GetFolderPath();
}
/// <summary>
/// Opens a File Dialog for user to select the file
/// </summary>
/// <param name="parameter">FolderDialogUserControl.xaml.cs file</param>
private void BrowseFileDialog(object parameter)
{
RestoreSource = (parameter as IDialogResults)?.GetFilePath();
}
Aside normal folder browser feel tradeoff (which was hardly noticeable by users), everything worked fine.