在VS . net中,当你为项目选择文件夹时,会显示一个类似于OpenFileDialog或SaveFileDialog的对话框,但设置为只接受文件夹。自从我看到这个,我就想知道它是怎么做到的。我知道FolderBrowserDialog,但我从来都不喜欢那个对话框。它开始太小,不让我利用能够键入路径的优势。

到目前为止,我几乎可以肯定在。net中没有办法做到这一点,但我很好奇在非托管代码中如何做到这一点。如果不从头开始完全重新实现对话框,如何修改对话框以使其具有这种行为呢?

我还想重申,我知道FolderBrowserDialog,但有时我不喜欢使用它,除了真正好奇如何以这种方式配置对话框。告诉我只使用FolderBrowserDialog可以帮助我保持一致的UI体验,但不能满足我的好奇心,所以它不能算作答案。

It's not a Vista-specific thing either; I've been seeing this dialog since VS .NET 2003, so it is doable in Win2k and WinXP. This is less of a "I want to know the proper way to do this" question and more of a "I have been curious about this since I first wanted to do it in VS 2003" question. I understand that Vista's file dialog has an option to do this, but it's been working in XP so I know they did something to get it to work. Vista-specific answers are not answers, because Vista doesn't exist in the question context.

更新:我接受Scott Wisniewski的答案,因为它附带了一个工作示例,但我认为Serge值得赞扬,因为他指出了对话框定制(这在。net中确实很讨厌,但它确实有效),Mark Ransom指出微软可能为这个任务推出了一个自定义对话框。


当前回答

试试下面这个来自Codeproject(归功于Nitron):

我认为这是相同的对话框,如果你添加一个截图可能会有所帮助?

bool GetFolder(std::string& folderpath, const char* szCaption=NULL, HWND hOwner=NULL)
{
    bool retVal = false;

    // The BROWSEINFO struct tells the shell how it should display the dialog.
    BROWSEINFO bi;
    memset(&bi, 0, sizeof(bi));

    bi.ulFlags   = BIF_USENEWUI;
    bi.hwndOwner = hOwner;
    bi.lpszTitle = szCaption;

    // must call this if using BIF_USENEWUI
    ::OleInitialize(NULL);

    // Show the dialog and get the itemIDList for the selected folder.
    LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi);

    if(pIDL != NULL)
    {
        // Create a buffer to store the path, then get the path.
        char buffer[_MAX_PATH] = {'\0'};
        if(::SHGetPathFromIDList(pIDL, buffer) != 0)
        {
            // Set the string value.
            folderpath = buffer;
            retVal = true;
        }       

        // free the item id list
        CoTaskMemFree(pIDL);
    }

    ::OleUninitialize();

    return retVal;
}

其他回答

您可以使用folderbrowserdialgex - 内置FolderBrowserDialog的可重用衍生物。这个选项允许您输入路径,甚至是UNC路径。你也可以用它浏览电脑或打印机。工作原理就像内置的FBD,但是…更好。

(编辑:我应该指出这个对话框可以设置为选择文件或文件夹。)

完整的源代码(一个简短的c#模块)。免费的。微软公开许可。

使用它的代码:

var dlg1 = new Ionic.Utils.FolderBrowserDialogEx();
dlg1.Description = "Select a folder to extract to:";
dlg1.ShowNewFolderButton = true;
dlg1.ShowEditBox = true;
//dlg1.NewStyle = false;
dlg1.SelectedPath = txtExtractDirectory.Text;
dlg1.ShowFullPathInEditBox = true;
dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer;

// Show the FolderBrowserDialog.
DialogResult result = dlg1.ShowDialog();
if (result == DialogResult.OK)
{
    txtExtractDirectory.Text = dlg1.SelectedPath;
}

试试下面这个来自Codeproject(归功于Nitron):

我认为这是相同的对话框,如果你添加一个截图可能会有所帮助?

bool GetFolder(std::string& folderpath, const char* szCaption=NULL, HWND hOwner=NULL)
{
    bool retVal = false;

    // The BROWSEINFO struct tells the shell how it should display the dialog.
    BROWSEINFO bi;
    memset(&bi, 0, sizeof(bi));

    bi.ulFlags   = BIF_USENEWUI;
    bi.hwndOwner = hOwner;
    bi.lpszTitle = szCaption;

    // must call this if using BIF_USENEWUI
    ::OleInitialize(NULL);

    // Show the dialog and get the itemIDList for the selected folder.
    LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi);

    if(pIDL != NULL)
    {
        // Create a buffer to store the path, then get the path.
        char buffer[_MAX_PATH] = {'\0'};
        if(::SHGetPathFromIDList(pIDL, buffer) != 0)
        {
            // Set the string value.
            folderpath = buffer;
            retVal = true;
        }       

        // free the item id list
        CoTaskMemFree(pIDL);
    }

    ::OleUninitialize();

    return retVal;
}

Ookii。对话框包包含一个托管包装器围绕新的(vista风格)文件夹浏览器对话框。它在旧的操作系统上也会优雅地退化。

面向。net 4.5的WPF Ookii对话框,在NuGet上可用 面向。net 4.5的Windows窗体Ookii对话框,可在NuGet上使用

我知道这个问题是关于OpenFileDialog的配置,但看到谷歌把我带到这里,我不妨指出,如果你只是在寻找文件夹,你应该使用FolderBrowserDialog,而不是下面另一个SO问题的答案

如何指定路径使用打开文件对话框在vb.net?

最好使用FolderBrowserDialog。

using (FolderBrowserDialog dlg = new FolderBrowserDialog())
{
    dlg.Description = "Select a folder";
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        MessageBox.Show("You selected: " + dlg.SelectedPath);
    }
}