C# OpenFileDialog 默认路径

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9980262/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 11:28:48  来源:igfitidea点击:

OpenFileDialog default path

c#

提问by Eu Lupu

using (var openFileDialog1 = new OpenFileDialog())
        {
            openFileDialog1.Reset();
            if (!string.IsNullOrEmpty(ExcelFilePath))
            {
                string fileName = Path.GetFileName(ExcelFilePath);
                string fileExt = Path.GetExtension(ExcelFilePath);
                //Avoid "you can't open this location using this program file" dialog 
                //if there is a file name in the path strip it )
                if (!string.IsNullOrEmpty(fileName))
                    initialDirectory = Path.GetDirectoryName(ExcelFilePath);  
      //if not let it be   
                else
                    initialDirectory = ExcelFilePath;

            openFileDialog1.InitialDirectory = initialDirectory;
            }
            else
                openFileDialog1.InitialDirectory = "c:\";
            openFileDialog1.Filter = "Excel files (*.xls or *.xlsx)|*.xls;*.xlsx";
            //openFileDialog1.Filter = "xls files (*.xls)|*.xls|xlsx files(*.xlsx)|.xlsx";
            openFileDialog1.FilterIndex = 2;
            openFileDialog1.RestoreDirectory = false;
            openFileDialog1.CheckFileExists = true;
            openFileDialog1.CheckPathExists = true;
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                var browseSelectionMade = BrowseSelectionMade;
                if (browseSelectionMade!=null)
                    browseSelectionMade(this, new DataEventArgs<string>(openFileDialog1.FileName));
            }
        }

Regardless of whether or not I set RestoreDirectory to true, I will always browse to the LAST used directory if my initial directory is set to a path that doesn't exist. Where is the last used directory saved by OpenFileDialog? And is there a way to override this behavior? (e.g. I always want to set it to C:\ if the initial directory doesn't exist?)

无论我是否将 RestoreDirectory 设置为 true,如果我的初始目录设置为不存在的路径,我将始终浏览到最后使用的目录。OpenFileDialog 保存的最后使用的目录在哪里?有没有办法覆盖这种行为?(例如,如果初始目录不存在,我总是想将其设置为 C:\?)

采纳答案by Hans Passant

Where is the last used directory saved?

上次使用的目录保存在哪里?

It is stored in the registry. The exact location depends on the Windows version, for Win7 it is HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32. A quick look with regedit ought to convince you that you don'twant to mess with that.

它存储在注册表中。确切位置取决于 Windows 版本,对于 Win7,它是 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32。就让我们来看看与注册表编辑器应该说服你,你希望与那些乱七八糟。

The simple workaround is to provide a valid path. If the one you calculate isn't valid, Directory.Exists returns false, then provide a valid one. Like the Documents folder returned by Environment.GetFolderPath(). Then again, nothing wrong with the last used one either, the user will easily recognize it with good odds that it happens to be close to the desired one.

简单的解决方法是提供有效路径。如果您计算的那个无效,Directory.Exists 返回 false,然后提供一个有效的。就像 Environment.GetFolderPath() 返回的 Documents 文件夹一样。再说一次,最后使用的也没有问题,用户很容易识别它,很有可能它恰好接近所需的。

回答by rie819

Check to see if the ExcelFilePath exists, you check to see if it's null or empty, however if before your block you check to see if the directory exists, and if it doesn't reset the value to an empty string you should be golden.

检查 ExcelFilePath 是否存在,您检查它是否为空或空,但是如果在您的块之前检查目录是否存在,并且如果它没有将值重置为空字符串,您应该是黄金。

(yes you'll need to apply your file name logic etc earlier) however once you've parsed all of that out, it's trivial to determine if the directory exits

(是的,你需要更早地应用你的文件名逻辑等)但是一旦你解析了所有这些,确定目录是否存在就很简单了

if (!Directory.Exists(excelPath))
{
    ExcelFilePath = String.Empty;
}

回答by Jetti

It seems like all you need to do is the following:

似乎您需要做的就是以下内容:

string path; // this is the path that you are checking.
if(Directory.Exists(path)) {
    openFileDialog1.InitialDirectory = path;
} else {
    openFileDialog1.InitialDirectory = @"C:\";
} 

That is unless I'm missing something.

除非我遗漏了什么。

回答by Du D.

I don't think there is anything built in for that. Just check before you open the dialog:

我不认为有任何内置的东西。在打开对话框之前检查一下:

if (!Directory.Exists(initialDirectory))
{
    openFileDialog1.InitialDirectory = @"C:\";
}

回答by DeveloperDan

Also, to set the default extension you should set FilterIndex property instead of DefaultExt. see: https://stackoverflow.com/a/6104319/381082

此外,要设置默认扩展名,您应该设置 FilterIndex 属性而不是 DefaultExt。见:https: //stackoverflow.com/a/6104319/381082

Here's a good article on the OpenFileDialog in C#: http://www.c-sharpcorner.com/uploadfile/mahesh/openfiledialog-in-C-Sharp/

这是一篇关于 C# 中 OpenFileDialog 的好文章:http: //www.c-sharpcorner.com/uploadfile/mahesh/openfiledialog-in-C-Sharp/

回答by Michal Pokluda

In case you're using file name stored in some string, it's better to use Path to cut the file name (on my W10 the open dialog doesn't open in initial directory, if I supply just file name):

如果您使用存储在某个字符串中的文件名,最好使用 Path 来剪切文件名(在我的 W10 上,如果我只提供文件名,则打开的对话框不会在初始目录中打开):

    if (!System.IO.Directory.Exists(filename))
    {
        openDlg.InitialDirectory =
            System.IO.Path.GetDirectoryName(filename);
    }

回答by Krzysztof Skowronek

For future me

为了未来的我

remember to do:

记得做:

            try        
            {
                result = dialog.ShowDialog(Window);
            }
            catch
            {
                dialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                result = dialog.ShowDialog(Window);
            }

This helps in the situation when user opened file from location, that does not longer exists (ex. USB stick, mapped network drive) - ShowDialog throws exception if InitialDirectory is invalid.

这有助于解决用户从不再存在的位置打开文件的情况(例如 U 盘、映射的网络驱动器) - 如果 InitialDirectory 无效,则 ShowDialog 抛出异常。

回答by Chipset31

Edit: After consulting with a more knowledgeable friend, perhaps the better solution is, in hindsight, obvious. Just store your own registry key in HKEY_CURRENT_USER\SOFTWARE\YourCompanyOrAppName\Whatevs or something similar (not sure on best practices, or which folders you have read/write access to, do your own research in that) and avoid this problem altogether. By simply letting the user navigate to where they want once, and then storing the path in the registry (as a normal string, and not a PIDL) and retrieving that path the next time. For reference, see the MSDN articles on the Registry and RegistryKey classes, and their example in the RegistryKey/Methods/SetValue article. Still, I'll leave this post as is, as a point of curiosity, or if someone has a very specific problem and needs this solution. As always, good luck!

编辑:在咨询了一位知识渊博的朋友之后,事后看来,也许更好的解决方案是显而易见的。只需将您自己的注册表项存储在 HKEY_CURRENT_USER\SOFTWARE\YourCompanyOrAppName\Whatevs 或类似的东西中(不确定最佳实践,或者您有读/写访问权限的文件夹,请自行研究)并完全避免这个问题。通过简单地让用户导航到他们想要的位置一次,然后将路径存储在注册表中(作为普通字符串,而不是 PIDL)并在下次检索该路径。如需参考,请参阅有关 Registry 和 RegistryKey 类的 MSDN 文章及其在 RegistryKey/Methods/SetValue 文章中的示例。尽管如此,作为好奇心,或者如果有人有非常具体的问题并需要此解决方案,我将保持原样。一如既往,祝你好运!

For any poor soul wandering through here in the future, it seems I figured out how to find the last used directory. Just like stated previously, it's stored in the registry, more specifically in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSavePidlMRU\Here is a set of folders for each file extension, including a "*" for unknown file extensions. I'll do this for txt files, change the path as needed. To access this path we make a RegistryKey and call OpenSubKey (BTW, full code below)

对于将来在这里徘徊的任何可怜的灵魂,我似乎想出了如何找到上次使用的目录。就像前面所说的,它存储在注册表中,更具体地说,HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSavePidlMRU\这里是每个文件扩展名的一组文件夹,包括一个“*”表示未知的文件扩展名。我将对 txt 文件执行此操作,根据需要更改路径。要访问此路径,我们创建一个 RegistryKey 并调用 OpenSubKey(顺便说一句,完整代码如下)

string RegistryPath = @"Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSavePidlMRU\txt";
RegistryKey rk = Registry.CurrentUser.OpenSubKey(RegistryPath);

In here is a set of entries which all contain PIDLs (we'll get to that) of the last opened or saved items. DO NOTE: the folder name OpenSavePidlMRU, i've seen called just OpenSaveMRU, and seems to be for versions older than win 10. Also in here is an entry called "MRUListEx", MRU stands for "Most Recently Used". In this entry is an index of which item was... well, most recently used. So if I have 10 entries, named 0 to 9, and 9 was the last used, the first byte in MRUListEx will be 0x09. So for:

这里是一组条目,它们都包含上次打开或保存的项目的 PIDL(我们将介绍)。请注意:文件夹名称 OpenSavePidlMRU,我见过只称为 OpenSaveMRU,并且似乎适用于比 win 10 旧的版本。这里还有一个名为“MRUListEx”的条目,MRU 代表“最近使用过的”。在这个条目中是哪个项目的索引......好吧,最近使用过。因此,如果我有 10 个条目,命名为 0 到 9,并且 9 是最后使用的,则 MRUListEx 中的第一个字节将是 0x09。因此对于:

byte[] mrulistex = (byte[])rk.GetValue("MRUListEx");
byte Last = mrulistex[0];

Last will equal 0x09 (on my system) Then we call GetValue again but for that entry

最后将等于 0x09(在我的系统上)然后我们再次调用 GetValue 但对于该条目

byte[] LastPathByteArray = (byte[])rk.GetValue(Last.ToString());

And here's where things get problematic, as this won't return a byte array where each byte is a character in our filepath, it returns what's known as a PIDL. While the byte array will seem to contain the path, in both char and wide char, it also contains a bunch of gibberish that can't be easily converted. I won't pretend to understand it, but https://stackoverflow.com/a/4318663provides a way to convert this to a string. (see code below)

这就是问题所在,因为这不会返回一个字节数组,其中每个字节都是我们文件路径中的一个字符,它返回所谓的 PIDL。虽然字节数组似乎包含路径,在字符和宽字符中,它也包含一堆不能轻易转换的乱码。我不会假装理解它,但https://stackoverflow.com/a/4318663提供了一种将其转换为字符串的方法。(见下面的代码)

string LastPath = GetPathFromPIDL(LastPathByteArray);

And we're done. PLEASE NOTE this doesn't necessarily represent a good solution, but I wasn't able to find much official documentation on this in my half hour of digging. And obviously this code doesn't check if the registry path is correct, if the registry keys exist, or do much error checking at all, but this does at least work.

我们已经完成了。请注意,这并不一定代表一个好的解决方案,但在我的半小时挖掘中,我无法找到太多关于此的官方文档。很明显,这段代码不会检查注册表路径是否正确,注册表项是否存在,或者根本不进行大量错误检查,但这至少可以工作。

using Microsoft.Win32; //for the registry class
using System.Runtime.InteropServices; //for converting the PIDL

//GetPathFromPIDL from matt.schechtman at https://stackoverflow.com/a/4318663
[DllImport("shell32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SHGetPathFromIDListW(IntPtr pidl, MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszPath);
private string GetPathFromPIDL(byte[] byteCode)
{
    //MAX_PATH = 260
    StringBuilder builder = new StringBuilder(260);

    IntPtr ptr = IntPtr.Zero;
    GCHandle h0 = GCHandle.Alloc(byteCode, GCHandleType.Pinned);
    try
    {
        ptr = h0.AddrOfPinnedObject();
    }
    finally
    {
        h0.Free();
    }

    SHGetPathFromIDListW(ptr, builder);

    return builder.ToString();
}

public void OnClick_Button_OpenFile(object sender, RoutedEventArgs e)
{
    string RegistryPath = @"Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSavePidlMRU\txt";
    RegistryKey rk = Registry.CurrentUser.OpenSubKey(RegistryPath);
    byte[] mrulistex = (byte[])rk.GetValue("MRUListEx");
    byte Last = mrulistex[0];
    byte[] LastPathByteArray = (byte[])rk.GetValue(Last.ToString());
    string LastPath = GetPathFromPIDL(LastPathByteArray);

    // Configure open file dialog box
    Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();`
    dlg.InitialDirectory = LastPath;
    result = dlg.ShowDialog();
    if (result == true)
    {
        string filename = dlg.FileName;
    }
    //etc etc, rest of your code
}

Good luck.

祝你好运。