1

I am trying to replicate some behaviour from Microsoft Word around the Save File Dialog. In Word (Office 365 Latest Version) if you go to Save As and bring up the browse dialog, the default directory is My Documents, if you then change the Save as type to "Word Template (*.dotx)" this automatically takes you to the "Custom Office Templates" folder. This is the behaviour I want to replicate.

As far as I am aware this is not possible out of the box in WPF using the Microsoft.Win32.SaveFileDialog, please correct me if I am wrong.

So I have tried to use the CommonSaveFileDialog from the Microsoft.WindowsAPICodePack.Shell Nuget package. I believe I am very close, but I can't seem to get it to actually do the navigation part when a type is changed. Please see the code below, any advice is greatly appreciated. I need this for a WPF desktop application.

CommonSaveFileDialog saveDialog;
private void Button_Click(object sender, RoutedEventArgs e)
{
    saveDialog = new CommonSaveFileDialog();
    saveDialog.Filters.Add(new CommonFileDialogFilter("My File", ".mf"));
    saveDialog.Filters.Add(new CommonFileDialogFilter("My Template File", ".mft"));

    saveDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

    saveDialog.FileTypeChanged += saveDialog_FileTypeChanged;

    saveDialog.ShowDialog();
}

private void saveDialog_FileTypeChanged(object sender, EventArgs e)
{
    var selectedSaveAsType = saveDialog.Filters[saveDialog.SelectedFileTypeIndex - 1];

    if (selectedSaveAsType.DisplayName == "My Template File (*.mft)")
    {   
        //These don't cause a navigation... How can I achieve this?
        //saveDialog.InitialDirectory = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "My Application Templates");
        //saveDialog.DefaultDirectory = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "My Application Templates");
    } 
    else
    {
        //saveDialog.DefaultDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    }
}

If you need any further information, let me know. Thank you in advance for any advice. :)

There does not appear to be any .CurrentDirectory or .Path property. Or any sort of Navigate method.

Ryan Thomas
  • 1,724
  • 2
  • 14
  • 27

2 Answers2

1

After searching for some sort method / property to change folder using .GetType().GetMethods() there was still nothing. So I decompiled the DLL using dnSpy, and this led to me finding a SetFolder method in the IFileDialog.

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);

The only way I could achieve my goal was to clone the GitHub repo for the Nuget package and add to it myself. I added the following public method to the CommonFileDialog class.

public void SetFolder(string folderPath)
{
    // Create a native shellitem from our path
    // Add some proper error handling to ensure directory exists....
    Guid guid = new Guid(ShellIIDGuid.IShellItem2);
    IShellItem2 defaultDirectoryShellItem;
    ShellNativeMethods.SHCreateItemFromParsingName(folderPath, IntPtr.Zero, ref guid, out defaultDirectoryShellItem);
    nativeDialog.SetFolder(defaultDirectoryShellItem);
}

Then I can use this in my application simply by calling

dialog.SetFolder(@"C:\");
Ryan Thomas
  • 1,724
  • 2
  • 14
  • 27
0

It doesn't seem like CommonSaveFileDialog exposes any properties that let you set the current directory- at least not that I can find.

I you really want to do this, you might have to dig under the hood. CommonSaveFileDialog uses the native Common Dialog Box Library internally. There might be a method that lets you do what you want at that level, you'd have to look through the documentation. If so, you could just call it directly p/invoke style.

Keith Stein
  • 6,235
  • 4
  • 17
  • 36
  • Thanks Keith. I did do a GetMethods() on the type to have a look, but wasn't any. Eventually I decompiled the DLL and dug around and found a Set Folder method. I cloned the repo and added a public method to call this. I will share my anwser tomorrow. Maybe this was the kick I needed to start contributing to stuff on GitHub ha. – Ryan Thomas May 21 '20 at 22:01