tom greene
tom greene

Reputation: 5449

Setting the initial directory of an SaveFileDialog?

I'd like a SaveFileDialog with the following behavior:

If I don't set the InitialDirectory, it goes to the exe's directory - which is not what I want. It rememebers the last selected directory though - even between executions.

If I set the InitialDirectory, it does not remember the last selected directory. Of course, I could save the last selected directory in the registry :( but I am looking for a better solution.

      SaveFileDialog dialog = new SaveFileDialog();
      //??? dialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
      dialog.ShowDialog();

Any advice?

Upvotes: 40

Views: 70573

Answers (15)

MaxOvrdrv
MaxOvrdrv

Reputation: 1916

In case anyone is looking to do this the proper way... just follow this MSDN article and everything will work properly: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.filedialog.initialdirectory?view=net-5.0

And yes: this can be done dynamically... smart way to keep track is to use a textbox control as a "last path" reference... mind you most interfaces will already be showing a path textbox on the form, in which case, just use that one... note also here the fallback to MyDocuments if the folder does not exist...

Example:

Your form here is expected to have your typical Label, TextBox and "Browse" Button trio for 2 different file path lookups, but as you can see I use the same OpenFileDialog instance to setup both dialogs when their respective browse buttons are pushed:

    private void btn_KnownServersFilePath_Browse_Click(object sender, EventArgs e)
    {

        string tmppath = Path.GetDirectoryName(this.txt_Servers_TemplatePath.Text) + "\\";
        this.openFileDialog1.InitialDirectory = Directory.Exists(tmppath) ? tmppath : Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        this.openFileDialog1.Filter = "excel files (*.xlsx)|*.xlsx|All files (*.*)|*.*";
        this.openFileDialog1.FilterIndex = 2;
        this.openFileDialog1.RestoreDirectory = true;
        this.openFileDialog1.FileName = Path.GetFileName(this.txt_Servers_TemplatePath.Text);
        

        if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
            this.txt_Servers_TemplatePath.Text = this.openFileDialog1.FileName;
    }

    private void btn_ServerDumpFilePath_Browse_Click(object sender, EventArgs e)
    {
        string tmppath = Path.GetDirectoryName(this.txt_AllOU_TemplatePath.Text) + "\\";
        this.openFileDialog1.InitialDirectory = Directory.Exists(tmppath) ? tmppath : Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        this.openFileDialog1.Filter = "AD dump files (*.csv)|*.csv|All files (*.*)|*.*";
        this.openFileDialog1.FilterIndex = 2;
        this.openFileDialog1.RestoreDirectory = true;
        this.openFileDialog1.FileName = Path.GetFileName(this.txt_AllOU_TemplatePath.Text);

        if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
            this.txt_AllOU_TemplatePath.Text = this.openFileDialog1.FileName;
    }

Upvotes: 0

Pixel_95
Pixel_95

Reputation: 984

use the saveFileDialog.InitialDirectory property as follows:

Stream stream;
SaveFileDialog saveFileDialog = new SaveFileDialog();

saveFileDialog.Filter = "dat files (*.dat)|*.dat|All files (*.*)|*.*";
saveFileDialog.FilterIndex = 1;
saveFileDialog.RestoreDirectory = true;
saveFileDialog.InitialDirectory = @"D:\Data\...\foldername\";
saveFileDialog.ShowDialog();

if (!saveFileDialog.FileName.Equals(string.Empty))
    Console.WriteLine(saveFileDialog.FileName);

Upvotes: 0

Andrew Mills
Andrew Mills

Reputation: 1

'In terms of saving an output file to a desired directory in vb.net, 'the following was the way I found that worked like a charm:

Dim filcsv As String = fileNamey.Replace(".txt", "_Denied2.csv")
Dim filcsv2 As String = fileNamey.Replace(".txt", "_Approved2.csv")

Dim outputDirectory As String = "C:\Users\jlcmil\Documents\EnableMN\output\"
Dim totalPath As String = System.IO.Path.Combine(outputDirectory, filcsv)
Dim totalPath2 As String = System.IO.Path.Combine(outputDirectory, filcsv2)

Dim outDenied As StreamWriter = New StreamWriter(totalPath)
Dim outApproved As StreamWriter = New StreamWriter(totalPath2)

Upvotes: 0

Andreas Aalsaunet
Andreas Aalsaunet

Reputation: 1

Just wanted to weigh in on this discussion (a couple of years too late) as I had exact problem too. Even though one is led to believe that this behavior - i.e using a default path the first time and then the previous selected path after that - can be achieved by using openFileDialog's properties and functions, one simply can't (per now)!

One could change the working directory to the desired default path (e.g. Environment.CurrentDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);) but some framework, like Unity, doesn't like this very much and terminates.

Because of this I ended up with this code:

private bool firstDialogOpened = true;

public void BrowseFiles()
{
    OpenFileDialog openFileDialog = new OpenFileDialog();
    openFileDialog.Filter = "Model files (*.obj)|*.obj|All files (*.*)|*.*";
    openFileDialog.FilterIndex = 1;

    if (firstDialogOpened)
    {
        openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
        firstDialogOpened = false;
    }

    if (openFileDialog.ShowDialog() == DialogResult.OK)
        filepath.text = openFileDialog.FileName;
}

This gives the desired behavior for me, although I would have loved a more elegant solution.

Upvotes: 0

vapcguy
vapcguy

Reputation: 7537

This is what I ended up with, that goes along with where the OP wanted to point their dialog:

Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.InitialDirectory = null;

// May or may not want "saves", but this shows how to append subdirectories
string path = (Path.Combine(Environment.ExpandEnvironmentVariables("%USERPROFILE%"), "My Documents") + "\\saves\\");  

if (!Directory.Exists(path))
    Directory.CreateDirectory(path);

dlg.InitialDirectory = path;
dlg.RestoreDirectory = true;

if (dlg.ShowDialog().Value == true)
{
    // This is so you can have JUST the directory they selected
    path = dlg.FileName.Remove(dlg.FileName.LastIndexOf('\\'), dlg.FileName.Length - dlg.FileName.LastIndexOf('\\'));

    string filePath = Path.Combine(path, fileName);

    // This is "just-in-case" - say they created a new directory in the dialog,
    // but the dialog doesn't seem to think it exists because it didn't see it on-launch?
    if (!Directory.Exists(path))
        Directory.CreateDirectory(path);

    // Remove a file if it has the same name
    if (File.Exist(filePath))
        File.Delete(filePath);

    // Write the file, assuming you have and pass in the bytes
    using (FileStream fs = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write)
    {
        fs.Write(bytes, 0, (int)bytes.Length);
        fs.Close();
    }
}

Upvotes: 0

user104933
user104933

Reputation: 21

I found that setting InitialDirectory to null first works around user history.

    OpenFileDialog dlgOpen = new OpenFileDialog();
    dlgOpen.InitialDirectory = null;
    dlgOpen.InitialDirectory = @"c:\user\MyPath";

Upvotes: 2

danio
danio

Reputation: 8653

The suggested workarounds didn't work for me, so after finding How does WPF OpenFileDialog track directory of last opened file? I implemented:

public static void SetInitialDirectory(this FileDialog dlg, string fileExtension, string initialDirectory)
        {
            // RestoreDirectory doesn't seem to be implemented - https://stackoverflow.com/questions/11144770/how-does-wpf-openfiledialog-track-directory-of-last-opened-file
            // so manually only set InitialDirectory if nothing is stored
            try
            {
                var mru = @"Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSavePidlMRU\" + fileExtension;
                var rk = Registry.CurrentUser.OpenSubKey(mru);
                if (rk == null)
                {
                    dlg.InitialDirectory = initialDirectory;
                }
            }
            catch (Exception)
            {
                // SecurityException, ObjectDisposedException => allow default behaviour
            }
        }

This will use the provided initialDirectory if the dialog has not been used before for this file extension. Once the dialog has been used, it reverts to the default behaviour of remembering the previous directory.

Upvotes: 2

OhBeWise
OhBeWise

Reputation: 5454

None of the provided solutions worked for me sadly.

In addition to the OP specifications, I wanted the program to remember the last save location between runs. For this, in the Visual Studios Solution Explorer under ProjectName -> Properties -> Settings.settings, I setup the following property:

Settings.settings property: Name=PreviousPath, Type=string, Scope=User, leave Value empty

Because I am keeping the SaveFileDialog around for the duration of the program's running, I instantiate at the start. Then in the Command for bringing up the dialog:

if (string.IsNullOrEmpty(Settings.Default.PreviousPath))
{
    this.saveDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
}
else
{
    this.saveDialog.InitialDirectory = Settings.Default.PreviousPath;
}

this.saveDialog.FileName = "Default_File_Name";

bool result = this.saveDialog.ShowDialog() ?? false;

if (result)
{
    Settings.Default.PreviousPath = Path.GetDirectoryName(this.saveDialog.FileName);
    Settings.Default.Save();

    // Code writing to the new file...
}

This gives the behavior:

  • First time the program is run and dialog is opened, it navigates to "My Documents".
  • Consecutive runs and dialog opened:
    • If saved on a previous open, it navigates to previous save location.
    • If not saved on a previous open, navigates to "My Documents".

Upvotes: 1

PauLEffect
PauLEffect

Reputation: 423

savefiledialog.InitialDirectory = Application.StartupPath;
savefiledialog.RestoreDirectory = true;

tested a second ago.

Upvotes: 0

Ali Akbar
Ali Akbar

Reputation: 794

If you use forward slash anywhere in your path, InitialDirectory does not work. Make sure they are converted to back slashes

Upvotes: 0

user1956901
user1956901

Reputation: 81

Make sure to check that the directory path exists before setting the Initial directory property. Create the directory if it does not exist. ie

if (!Directory.Exists(FooDirectory))
{
     Directory.CreateDirectory(FooDirectory);
}

Upvotes: 5

mousio
mousio

Reputation: 10337

I too have tried different "solutions" found in different places, but none of them seem to work as soon as there is an MRU list entry in the registry :/ But here is my own simple workaround…

Instead of setting the dialog's InitialDirectory property, set the FileName property to your path, but combined with the selected Filter, e.g.:

dialog.FileName = Path.Combine(myPath, "*.*");

Upvotes: 3

Jeffrey Harmon
Jeffrey Harmon

Reputation: 2437

I have no idea why this works, but I was finally able to get it working for me.

I found that if I gave the full path, it would not work, but if I put that full path inside of Path.GetFullPath(), then it would work. Looking at the before and after values show them being the same, but it would consistently not work without it, and work with it.

//does not work
OpenFileDialog dlgOpen = new OpenFileDialog();
string initPath = Path.GetTempPath() + @"\FQUL";
dlgOpen.InitialDirectory = initPath;
dlgOpen.RestoreDirectory = true;

//works
OpenFileDialog dlgOpen = new OpenFileDialog();
string initPath = Path.GetTempPath() + @"\FQUL";
dlgOpen.InitialDirectory = Path.GetFullPath(initPath);
dlgOpen.RestoreDirectory = true;

Upvotes: 22

Icono123
Icono123

Reputation: 3950

I did some testing with .NET 2.0 and it seems if I set FileName to anything other than a literal string it doesn't work. When I use a method or accesstor to set the property the initial directory is ignored.

Upvotes: 0

Andrew Hare
Andrew Hare

Reputation: 351476

You need to set the RestoreDirectory to true as well as the InitialDirectory property.

Upvotes: 37

Related Questions