在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;
}
在Vista上,你可以使用IFileDialog和FOS_PICKFOLDERS选项集。这将导致显示类似于openfiledialog的窗口,您可以在其中选择文件夹:
var frm = (IFileDialog)(new FileOpenDialogRCW());
uint options;
frm.GetOptions(out options);
options |= FOS_PICKFOLDERS;
frm.SetOptions(options);
if (frm.Show(owner.Handle) == S_OK) {
IShellItem shellItem;
frm.GetResult(out shellItem);
IntPtr pszString;
shellItem.GetDisplayName(SIGDN_FILESYSPATH, out pszString);
this.Folder = Marshal.PtrToStringAuto(pszString);
}
对于旧的Windows系统,你可以选择文件夹中的任何文件。
在。net Framework 2.0及更高版本上的工作示例可以在这里找到。