Why FolderBrowserDialog dialog does not scroll to selected folder?

前端 未结 14 1528
失恋的感觉
失恋的感觉 2020-11-30 02:28

As show in this screen shot, the selected folder is not in the view. It needs to be scrolled down to view the selected folder.

相关标签:
14条回答
  • 2020-11-30 02:39

    dlgFolder.RootFolder = Environment.SpecialFolder.DesktopDirectory;

    is not the same as

    dlgFolder.RootFolder = Environment.SpecialFolder.Desktop;

    What's the difference between SpecialFolder.Desktop and SpecialFolder.DesktopDirectory?

    The thread linked indicates that as a path, they do get the same result. But they are not the same, as one is a logical path and the other is a physical path.

    I have found when either one is assigned to the RootFolder of the open folder dialog, the resulting behavior can be different.

    As a .RootFolder assignment, some versions of windows, like win7, treat either one as "Desktop". That is, you can see the "Computer" sub-entry, and open that to see the individual drive letters. The .SelectedPath gets selected either way, but the selected path is only made visible when the logical path of the desktop is assigned to the .RootFolder.

    Worse, when using the browse folder dialog in win10 pre-release, it appears that "DesktopDirectory" as just that, the contents of the Desktop Directory only, with no link whatsoever to the logical desktop directory. And not listing any sub-items under it. Very frustrating if an app written for win7 is trying to be used with win10.

    I think the problem the OP is having is that they employed the physical desktop as the root, when they should have employed the logical desktop.

    I don't have an explanation for why the OP's two different machines respond differently. I would speculate that they have two different versions of the .NET framework installed.

    The fact that win10 prerelease has the "Stuck on Desktop" issue with the browse folder dialog may be due to the more recent .NET framework shipped with win10 prerelease. Unfortunately, I remain ignorant of all the facts in this (win10) case, as I have not updated yet.

    P.S. I found that win8 also experiences the "Stuck on Desktop" symptom:

    https://superuser.com/questions/869928/windows-8-1-folder-selection-dialog-missing-my-computer-and-sub-items

    The workaround there was to select the alternate GUI in win8. Perhaps something similar can be done in win10 prerelease.

    0 讨论(0)
  • 2020-11-30 02:40

    on VB.Net code, just put this line of code right before showing the dialog.

    SendKeys.Send ("{TAB}{TAB}{RIGHT}")
    
    0 讨论(0)
  • 2020-11-30 02:44

    I have found that:

    1. If .SelectedPath ends with "\", the Dialog will scroll down to make the path visible.
    2. If .SelectedPath does not end with "\", the path is still selected, but not ensured visible.
    0 讨论(0)
  • 2020-11-30 02:51

    I have read the above discussion and solutions. Particularly Brat Oestreicher put me in the right direction. In essence, we must first find the TreeView control in the SHBrowseForFolder dialog, and send that window the TVM_ENSUREVISIBLE message. The following does this in C.

    #include <windows.h>
    #include <objbase.h>
    #include <objidl.h>
    #include <Shlobj.h>
    #include <Dsclient.h>
    #include <wchar.h>
    // 
    //  EnumCallback - Callback function for EnumWindows 
    // 
    static BOOL CALLBACK EnumCallback(HWND hWndChild, LPARAM lParam)
    {
       char szClass[MAX_PATH];
       HTREEITEM hNode;
       if (GetClassName(hWndChild, szClass, sizeof(szClass))
       &&  strcmp(szClass,"SysTreeView32")==0) {
          hNode = TreeView_GetSelection(hWndChild);    // found the tree view window
          TreeView_EnsureVisible (hWndChild, hNode);   // ensure its selection is visible
          return(FALSE);   // done; stop enumerating
       }
       return(TRUE);       // continue enumerating
    }
    // 
    //  BrowseCallbackProc - Callback function for SHBrowseForFolder 
    // 
    static INT CALLBACK BrowseCallbackProc (HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData) 
    {
        switch (uMsg) 
        { 
            case BFFM_INITIALIZED:
                SendMessage (hWnd, BFFM_SETEXPANDED, TRUE, lpData);    // expand the tree view
                SendMessage (hWnd, BFFM_SETSELECTION, TRUE, lpData);   // select the item
                break;
            case BFFM_SELCHANGED:
                EnumChildWindows(hWnd, EnumCallback,0);
                break;
        } 
        return 0; 
    } 
    // 
    //  SelectDirectory - User callable entry point 
    // 
    int SelectDirectory (HWND hWndParent, char *path, int pathSize) 
    { 
        BROWSEINFO bi = {0};
        LPITEMIDLIST pidl = NULL;
        wchar_t ws[MAX_PATH];
    
        CoInitialize(0);
        if (pathSize < MAX_PATH) return(FALSE);
    
        swprintf(ws, MAX_PATH, L"%hs", path);
    
        bi.hwndOwner = hWndParent; 
        bi.lpszTitle = "Select Directory"; 
        bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
        bi.lpfn = BrowseCallbackProc;
        bi.lParam = (LPARAM) ws;
    
        pidl = SHBrowseForFolder (&bi); 
        if (pidl != NULL) 
        { 
            LPMALLOC pMalloc = NULL; 
            SHGetPathFromIDList (pidl, path);
            path[pathSize-1]= '\0';
    
            SHGetMalloc(&pMalloc);
            pMalloc->lpVtbl->Free(pMalloc,pidl);    // deallocate item 
            pMalloc->lpVtbl->Release(pMalloc);
    
            return (TRUE);
        } 
        return (FALSE);
    } 
    

    Many thanks to Gary Beene.

    0 讨论(0)
  • 2020-11-30 02:53

    I know this thread is WAY old, but with extension methods, this can be added to the FolderBrowserDialog.ShowDialog method, and then used repeatedly where needed.

    The sample (below) is just using the easy SendKeys method (which I hate doing, but in this case, it works well). When using the SendKeys method to jump to the selected folder in the dialog, if you are debugging this in Visual Studio, then the SendKeys call applies to the current window, which would be the active VS window. To be more foolproof and to avoid the wrong window from getting the SendKeys message, then the extension method would contain the external method calls to send messages to the specific window similar to what Marc F posted, but translated to C#.

    internal static class FolderBrowserDialogExtension
    {
        public static DialogResult ShowDialog(this FolderBrowserDialog dialog, bool scrollIntoView)
        {
            return ShowDialog(dialog, null, scrollIntoView);
        }
    
        public static DialogResult ShowDialog(this FolderBrowserDialog dialog, IWin32Window owner, bool scrollIntoView)
        {
            if (scrollIntoView)
            {
                SendKeys.Send("{TAB}{TAB}{RIGHT}");
            }
    
            return dialog.ShowDialog(owner);
        }
    }
    
    0 讨论(0)
  • 2020-11-30 02:55

    The best approach, at least the most reliable is to make your own browser class dialog box. The tree scrolling issue has been a pain for many years - it will never get fixed!

    If you know how to render in paint there is not much you can't do.. fast in paint well that is another story.

    The first place I would look is at the open source .Net source code on GitHub, in your .Net version of choice, for the dialog class you're interested in improving. You may be surprised what you can achieve with a little effort and follow through. Just duplicate the control and debug to the point where the error occurs and patch - that'a what Microsoft does, so too can you!

    Since this is an old thread and posting samples may never get read. It would make more since to post if asked.

    Yet for someone looking to solve such an issue as with tree scrolling to the "expected" directory, here is some solid advise. If an issue exists with a control or library that has no immediate solution, create your own version, when possible extend the original and patch the problem. I've revamped everything from the Windows.Form.Control class to Win32 libraries for the sole purpose of getting predictable and accurate results.

    The good news is that with C# there is a lot of low level control available to achieve almost any reasonable objective and the is C too.

    In the past I have spent way too many hours searching for a solution to a problem where had I just recreated what was not working a lot of time would have been saved.

    0 讨论(0)
提交回复
热议问题