web-dev-qa-db-fra.com

Pourquoi la boîte de dialogue FolderBrowserDialog ne fait pas défiler jusqu'au dossier sélectionné?

Comme le montre cette capture d'écran, le dossier sélectionné n'est pas dans la vue. Il faut faire défiler l'écran pour afficher le dossier sélectionné.

enter image description here

La même boîte de dialogue affiche le dossier sélectionné visible sur un ordinateur différent

enter image description here

Je l'ai couru sur deux ordinateurs ayant Windows 7. Cela fonctionne correctement sur un, mais pas sur 2nd. Il semble quelque chose avec l'environnement Windows à la place un problème de code? Quelqu'un peut-il suggérer une solution?

Il n'y a pas de changement de code. J'ai utilisé des chemins plus longs à partir de différents lecteurs mais les résultats sont les mêmes.

private void TestDialog_Click ( object sender, EventArgs e )
        {
            //Last path store the selected path, to show the same directory as selected on next application launch.
            //Properties.Settings.Default.LastPath

            FolderBrowserDialog dlgFolder = new FolderBrowserDialog ();

            dlgFolder.RootFolder = Environment.SpecialFolder.DesktopDirectory;

            dlgFolder.SelectedPath = Properties.Settings.Default.LastPath;

            if (dlgFolder.ShowDialog () == System.Windows.Forms.DialogResult.OK)
            {

                Properties.Settings.Default.LastPath = dlgFolder.SelectedPath;               

                Properties.Settings.Default.Save ();
            }

        }
66
Munawar

Le problème fondamental est une mauvaise décision de conception dans la variable FolderBrowserDialog. Premièrement, nous devons réaliser que la FolderBrowserDialog n'est pas un contrôle .NET, mais plutôt le Common Dialog et fait partie de Windows. Le concepteur de cette boîte de dialogue a choisi de ne pas envoyer de message TVM_ENSUREVISIBLE au contrôle TreeView après l'affichage de la boîte de dialogue et la sélection d'un dossier initial. Ce message fait défiler un contrôle TreeView afin que l'élément actuellement sélectionné soit visible dans la fenêtre.

Donc, tout ce que nous avons à faire pour résoudre ce problème est d’envoyer le TreeView qui fait partie du message FolderBrowserDialog le TVM_ENSUREVISIBLE et tout ira bien. Droite? Eh bien, pas si vite. C’est effectivement la solution, mais certaines choses nous en empêchent.

  • Tout d’abord, parce que FolderBrowserDialog n’est pas vraiment un contrôle .NET, il n’a pas de collection Controls interne. Cela signifie que nous ne pouvons pas simplement rechercher et accéder au contrôle enfant TreeView à partir de .NET.

  • Deuxièmement, les concepteurs de la classe .NET FolderBrowserDialog ont décidé de seal cette classe. Cette décision malheureuse nous empêche d’en dériver et d’ignorer le gestionnaire de messages de fenêtre. Si nous avions pu le faire, nous aurions peut-être tenté de poster le message TVM_ENSUREVISIBLE lorsque nous aurions reçu le message WM_SHOWWINDOW dans le gestionnaire de messages.

  • Le troisième problème est que nous ne pouvons pas envoyer le message TVM_ENSUREVISIBLE tant que le contrôle Tree View n’existe pas en tant que fenêtre réelle et il n’existe pas tant que nous n’appelons pas la méthode ShowDialog. Cependant, cette méthode est bloquante et nous n’aurons donc pas l’opportunité de poster notre message une fois cette méthode appelée.

Pour résoudre ces problèmes, j'ai créé une classe d'assistance statique avec une seule méthode qui peut être utilisée pour afficher une variable FolderBrowserDialog et la faire défiler jusqu'au dossier sélectionné. Je parviens à cela en démarrant une Timer courte juste avant d'appeler la méthode ShowDialog du dialogue, puis en recherchant le handle du contrôle TreeView dans le gestionnaire Timer (c'est-à-dire après l'affichage de la boîte de dialogue) et l'envoi de notre message TVM_ENSUREVISIBLE.

Cette solution n’est pas parfaite car elle dépend de connaissances préalables sur FolderBrowserDialog. Plus précisément, je trouve le dialogue en utilisant son titre de fenêtre. Cela rompra avec les installations non anglaises. Je traque les contrôles enfants dans le dialogue en utilisant leurs ID d'élément de dialogue, plutôt que le texte du titre ou le nom de la classe, car j'estimais que ce serait plus fiable au fil du temps.

Ce code a été testé sur Windows 7 (64 bits) et Windows XP.

Voici le code: (Vous aurez peut-être besoin de: using System.Runtime.InteropServices;)

public static class FolderBrowserLauncher
{
    /// <summary>
    /// Using title text to look for the top level dialog window is fragile.
    /// In particular, this will fail in non-English applications.
    /// </summary>
    const string _topLevelSearchString = "Browse For Folder";

    /// <summary>
    /// These should be more robust.  We find the correct child controls in the dialog
    /// by using the GetDlgItem method, rather than the FindWindow(Ex) method,
    /// because the dialog item IDs should be constant.
    /// </summary>
    const int _dlgItemBrowseControl = 0;
    const int _dlgItemTreeView = 100;

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll")]
    static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    /// <summary>
    /// Some of the messages that the Tree View control will respond to
    /// </summary>
    private const int TV_FIRST = 0x1100;
    private const int TVM_SELECTITEM = (TV_FIRST + 11);
    private const int TVM_GETNEXTITEM = (TV_FIRST + 10);
    private const int TVM_GETITEM = (TV_FIRST + 12);
    private const int TVM_ENSUREVISIBLE = (TV_FIRST + 20);

    /// <summary>
    /// Constants used to identity specific items in the Tree View control
    /// </summary>
    private const int TVGN_ROOT = 0x0;
    private const int TVGN_NEXT = 0x1;
    private const int TVGN_CHILD = 0x4;
    private const int TVGN_FIRSTVISIBLE = 0x5;
    private const int TVGN_NEXTVISIBLE = 0x6;
    private const int TVGN_CARET = 0x9;


    /// <summary>
    /// Calling this method is identical to calling the ShowDialog method of the provided
    /// FolderBrowserDialog, except that an attempt will be made to scroll the Tree View
    /// to make the currently selected folder visible in the dialog window.
    /// </summary>
    /// <param name="dlg"></param>
    /// <param name="parent"></param>
    /// <returns></returns>
    public static DialogResult ShowFolderBrowser( FolderBrowserDialog dlg, IWin32Window parent = null )
    {
        DialogResult result = DialogResult.Cancel;
        int retries = 10;

        using (Timer t = new Timer())
        {
            t.Tick += (s, a) =>
            {
                if (retries > 0)
                {
                    --retries;
                    IntPtr hwndDlg = FindWindow((string)null, _topLevelSearchString);
                    if (hwndDlg != IntPtr.Zero)
                    {
                        IntPtr hwndFolderCtrl = GetDlgItem(hwndDlg, _dlgItemBrowseControl);
                        if (hwndFolderCtrl != IntPtr.Zero)
                        {
                            IntPtr hwndTV = GetDlgItem(hwndFolderCtrl, _dlgItemTreeView);

                            if (hwndTV != IntPtr.Zero)
                            {
                                IntPtr item = SendMessage(hwndTV, (uint)TVM_GETNEXTITEM, new IntPtr(TVGN_CARET), IntPtr.Zero);
                                if (item != IntPtr.Zero)
                                {
                                    SendMessage(hwndTV, TVM_ENSUREVISIBLE, IntPtr.Zero, item);
                                    retries = 0;
                                    t.Stop();
                                }
                            }
                        }
                    }
                }

                else
                {
                    //
                    //  We failed to find the Tree View control.
                    //
                    //  As a fall back (and this is an UberUgly hack), we will send
                    //  some fake keystrokes to the application in an attempt to force
                    //  the Tree View to scroll to the selected item.
                    //
                    t.Stop();
                    SendKeys.Send("{TAB}{TAB}{DOWN}{DOWN}{UP}{UP}");
                }
            };

            t.Interval = 10;
            t.Start();

            result = dlg.ShowDialog( parent );
        }

        return result;
    }
}
76
Brad Oestreicher

J'ai utilisé une solution de contournement de https://www.daniweb.com/software-development/csharp/threads/300578/folderbrowserdialog-expanding-the-selected-directory-

FolderBrowserDialog^ oFBD = gcnew FolderBrowserDialog;
oFBD->RootFolder = Environment::SpecialFolder::MyComputer;
oFBD->SelectedPath = i_sPathImport;
oFBD->ShowNewFolderButton = false;     // use if appropriate in your application
SendKeys::Send ("{TAB}{TAB}{RIGHT}");  // <<-- Workaround
::DialogResult oResult = oFBD->ShowDialog ();

Ce n'est pas la meilleure façon, mais ça marche pour moi.
Sans la RootFolder, cela ne fonctionnera PAS au premier appel, mais au 2e et suivants. Avec ça, ça marche toujours.

Comme d’autres ont observé que cette défaillance dépend du système d’exploitation:
J'utilise Win 7 Pro x64 SP1

7
Tobias Knauss

Je sais que ce fil est WAY old, mais avec les méthodes d'extension, cela peut être ajouté à la méthode FolderBrowserDialog.ShowDialog, puis utilisé à plusieurs reprises si nécessaire.

L'exemple (ci-dessous) utilise simplement la méthode facile SendKeys (ce que je n'aime pas faire, mais dans ce cas, cela fonctionne bien). Lorsque vous utilisez la méthode SendKeys pour accéder au dossier sélectionné dans la boîte de dialogue, si vous procédez au débogage dans Visual Studio, l'appel SendKeys s'applique à la fenêtre actuelle, qui serait la fenêtre VS active. Pour être plus sûr et éviter que le message SendKeys ne soit envoyé à la mauvaise fenêtre, la méthode d'extension contiendrait les appels de méthode externes pour envoyer des messages à la fenêtre spécifique, similaires à ce que Marc F a posté, mais traduits en 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);
    }
}
6
Brien Halstead

sur le code VB.Net, il suffit de mettre cette ligne de code juste avant d'afficher le dialogue.

SendKeys.Send ("{TAB}{TAB}{RIGHT}")
4
Loi Condes

J'ai lu sur différents forums que cela pourrait être dû à RootFolder parce que SelectedPath et RootFolder sont mutuellement exclusifs, cela signifie que les deux ne peuvent pas coexister, mais avec RootFolder (.Desktop) par défaut. Cela permet au moins de gravir l'arbre /Dossiers). 

Toutefois, si vous remplacez RootFolder par autre que le bureau, vous ne pourrez pas accéder aux chemins UNC.

Réponse à Hans Passant: J'ai essayé cette extension de dialogue, qui a TextBox, mais pas de chance.

Personnalisation de la boîte de dialogue de recherche de dossier pour afficher le chemin d'accès

3
Munawar

J'ai calculé quelque chose dans VB.NET, il serait donc facile de le transformer en C # . Je suis français et je suis débutant en VB . De toute façon, tu peux essayer ma solution.

Mon idée est de lancer une tâche asynchrone juste avant d’afficher le folderBrowserDialog.

J'ai trouvé cela moi-même, mais Brad m'a inspiré… .. Voici mon code:

Imports System.Threading.Tasks
Imports Microsoft.VisualBasic.FileIO.FileSystem

Public Enum GW
    HWNDFIRST = 0
    HWNDLAST = 1
    HWNDNEXT = 2
    HWNDPREV = 3
    OWNER = 4
    CHILD = 5
    ENABLEDPOPUP = 6
End Enum

Public Declare Function SendMessageW Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal msg As UInteger, ByVal wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lParam As String) As IntPtr
Public Declare Function FindWindowExW Lib "user32.dll" (ByVal hWndParent As IntPtr, ByVal hWndChildAfter As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszClass As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszWindow As String) As IntPtr
Public Declare Function GetWindow Lib "user32" (ByVal hwnd As IntPtr, ByVal wCmd As Long) As Long
Public Declare Function GetDesktopWindow Lib "user32" () As IntPtr
Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As IntPtr, ByVal lpClassName As System.Text.StringBuilder, ByVal nMaxCount As Integer) As Integer

Private Sub FolderBrowserDialog_EnsureVisible(FB As FolderBrowserDialog, _Owner As IntPtr)
    Dim hwnd As IntPtr
    Dim sClassname As New System.Text.StringBuilder(256)
    Thread.Sleep(50)                                     'necessary to let FolderBrowserDialog construct its window
    hwnd = GetDesktopWindow()                            'Desktop window handle.
    hwnd = GetWindow(hwnd, GW.CHILD)                     'We will find all children.
    Do Until hwnd = 0
        If GetWindow(hwnd, GW.OWNER) = _Owner Then       'If one window is owned by our main window...
            GetClassName(hwnd, sClassname, 255)
            If sClassname.ToString = "#32770" Then       'Check if the class is FolderBrowserDialog.
                Exit Do                                  'Then we found it.
            End If
        End If
        hwnd = GetWindow(hwnd, GW.HWNDNEXT)              'Next window.
    Loop                                                 'If no found then exit.
    If hwnd = 0 Then Exit Sub
    Dim hChild As IntPtr = 0
    Dim hTreeView As IntPtr = 0
    Dim i As Integer = 0
    Do
        i += 1
        If i > 1000 Then Exit Sub                                       'Security to avoid infinite loop.
        hChild = FindWindowExW(hwnd, hChild, Nothing, Nothing)          'Look for children windows of FolderBrowserDialog.
        hTreeView = FindWindowExW(hChild, 0, "SysTreeView32", Nothing)  'Look for treeview of FolderBrowserDialog.
        Thread.Sleep(5)                                                 'delay necessary because FolderBrowserDialog is in construction, then treeview maybe not yet exist.
    Loop While hTreeView = 0
    If SendMessageW(hwnd, &H46A, 1, FB.SelectedPath) = 0 Then           'Send message BFFM_SETEXPANDED to FolderBrowserDialog.
        SendMessageW(hTreeView, &H7, 0, Nothing)                        'Send message WM_SETFOCUS to the treeeview.
    End If
End Sub


Dim My_save_dir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) & "\My-Saves"

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim FolderBrowserDialog1 As New FolderBrowserDialog
    FolderBrowserDialog1.Description = "Choose your save files path."
    If Directory.Exists(My_save_dir) Then
        FolderBrowserDialog1.SelectedPath = My_save_dir
    Else
        FolderBrowserDialog1.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
    End If

    Dim Me_handle = Me.Handle         'Store the main handle to compare after with each windows owner.
    Task.Run(Sub() FolderBrowserDialog_EnsureVisible(FolderBrowserDialog1, Me_handle))      'Here's the trick, run an asynchronous task to modify the folderdialog.
    If FolderBrowserDialog1.ShowDialog(Me) = System.Windows.Forms.DialogResult.OK Then
        My_save_dir = FolderBrowserDialog1.SelectedPath
    End If
End Sub

J'attends vos suggestions… .. Et quelqu'un peut le traduire en C # parce que je ne le connais pas.

2
Marc F

J'ai trouvé que:

  1. Si .SelectedPath se termine par "\", le dialogue défilera vers le bas pour rendre le chemin visible.
  2. Si .SelectedPath ne se termine pas par "\", le chemin est toujours sélectionné, mais n'est pas visible visible.
2
René

Je rencontre le même problème dans c ++/mfc. Cela fonctionnait pour moi d'utiliser :: PostMessage plutôt que :: SendMessage dans le rappel BFFM_INITIALIZED pour placer le message TVM_ENSUREVISIBLE

    case BFFM_INITIALIZED: 
{
// select something
::SendMessage(m_hDialogBox, BFFM_SETSELECTION, TRUE, (LPARAM) pszSelection);


// find tree control
m_hTreeCtrl = 0;
HWND hchild = GetWindow(hWnd, GW_CHILD) ;
while (hchild != NULL)
{
  VS_TChar classname[200] ;
  GetClassName(hchild, classname, 200) ;

  if (VS_strcmp(classname, _T("SHBrowseForFolder ShellNameSpace Control")) == 0)
  {
    HWND hlistctrl = GetWindow(hchild, GW_CHILD) ;
    do
    { 
      GetClassName(hlistctrl, classname, 200) ;
      if (lstrcmp(classname, _T("SysTreeView32")) == 0)
      {
        m_hTreeCtrl = hlistctrl;
        break ;   
      }

      hlistctrl = GetWindow(hlistctrl, GW_HWNDNEXT) ;
    } while (hlistctrl != NULL);
  }      
  if (m_hTreeCtrl)
    break;
  hchild = GetWindow(hchild, GW_HWNDNEXT);      
}

if (m_hTreeCtrl)
{
  int item = ::SendMessage(m_hTreeCtrl, TVM_GETNEXTITEM, TVGN_CARET, 0);
  if (item != 0)             
    ::PostMessage(m_hTreeCtrl, TVM_ENSUREVISIBLE,0,item);
}
break;
}
2
Stefan_l_01

J'ai lu la discussion et les solutions ci-dessus. En particulier, Brat Oestreicher m'a mis dans la bonne direction. En substance, nous devons d'abord trouver le contrôle TreeView dans la boîte de dialogue SHBrowseForFolder et envoyer à cette fenêtre le message TVM_ENSUREVISIBLE. Ce qui suit fait cela en 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);
} 

Merci beaucoup à Gary Beene .

1
Paul Ogilvie

Ce lien a une réponse simple qui a bien fonctionné pour moi (j'ai Windows 8.1)

FolderBrowserDialog: Développer le répertoire sélectionné

0
user1760527

dlgFolder.RootFolder = Environment.SpecialFolder.DesktopDirectory;

n'est pas la même chose que

dlgFolder.RootFolder = Environment.SpecialFolder.Desktop;

Quelle est la différence entre SpecialFolder.Desktop et SpecialFolder.DesktopDirectory?

Le fil lié indique qu'en tant que chemin, ils obtiennent le même résultat. Mais ils ne sont pas identiques, l'un étant un chemin logique et l'autre un chemin physique.

J'ai constaté que lorsque l'un ou l'autre est affecté au dossier racine du dossier ouvert, le comportement résultant peut être différent.

En tant qu’affectation .RootFolder, certaines versions de Windows, telles que win7, traitent l’une ou l’autre comme "Bureau". C'est-à-dire que vous pouvez voir la sous-entrée "Ordinateur" et l'ouvrir pour voir les lettres de lecteur individuelles. Le chemin .SelectedPath est sélectionné d'une manière ou d'une autre, mais le chemin sélectionné n'est rendu visible que lorsque le chemin logique du bureau est affecté au dossier .RootFolder.

Pire encore, lors de l’utilisation de la boîte de dialogue Parcourir le dossier dans la version préliminaire de Win10, il apparaît que "DesktopDirectory" n’est que cela, le contenu du répertoire du bureau uniquement, sans aucun lien avec le répertoire du bureau logique. Et ne pas énumérer les sous-éléments en dessous. Très frustrant si une application écrite pour Win7 essaie d'être utilisée avec Win10.

Je pense que le problème des OP est qu’ils ont utilisé le bureau physique comme racine, alors qu’ils auraient dû utiliser le bureau logique.

Je n'ai pas d'explication sur la raison pour laquelle les deux machines du PO répondent différemment. Je supposerais qu'ils ont deux versions différentes du framework .NET installé.

Le fait que win10 prerelease ait le problème "Stuck on Desktop" avec la boîte de dialogue de navigation dans le dossier de navigation est peut-être dû au framework .NET plus récent fourni avec win10 prerelease. Malheureusement, je reste ignorant de tous les faits dans cette affaire (win10), car je n'ai pas encore mis à jour. 

P.S. J'ai trouvé que win8 éprouve également le symptôme "Stuck on Desktop":

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

La solution de contournement consistait à sélectionner l'interface graphique de remplacement dans win8. Peut-être que quelque chose de similaire peut être fait dans la version préliminaire de win10.

0
an odder guest

En réponse au message de Marc F - J'ai converti le VB.Net en C #

    public enum GW
    {
        HWNDFIRST = 0,
        HWNDLAST = 1,
        HWNDNEXT = 2,
        HWNDPREV = 3,
        OWNER = 4,
        CHILD = 5,
        ENABLEDPOPUP = 6
    }

    [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SendMessageW", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern IntPtr SendMessageW(IntPtr hWnd, uint msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
    [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindowExW", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern IntPtr FindWindowExW(IntPtr hWndParent, IntPtr hWndChildAfter, [MarshalAs(UnmanagedType.LPWStr)] string lpszClass, [MarshalAs(UnmanagedType.LPWStr)] string lpszWindow);
    [System.Runtime.InteropServices.DllImport("user32", EntryPoint = "GetWindow", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern UInt32 GetWindow(IntPtr hwnd, UInt32 wCmd);
    [System.Runtime.InteropServices.DllImport("user32", EntryPoint = "GetDesktopWindow", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern IntPtr GetDesktopWindow();
    [System.Runtime.InteropServices.DllImport("user32", EntryPoint = "GetClassNameA", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern int GetClassName(IntPtr hwnd, System.Text.StringBuilder lpClassName, int nMaxCount);

    private void FolderBrowserDialog_EnsureVisible(FolderBrowserDialog FB, IntPtr _Owner)
    {
        IntPtr hwnd = System.IntPtr.Zero;
        System.Text.StringBuilder sClassname = new System.Text.StringBuilder(256);
        Thread.Sleep(50); //necessary to let FolderBrowserDialog construct its window
        hwnd = GetDesktopWindow(); //Desktop window handle.
        hwnd = (System.IntPtr)GetWindow(hwnd, (UInt32)GW.CHILD); //We will find all children.
        while (!(hwnd == (System.IntPtr)0))
        {
            if (GetWindow(hwnd, (UInt32)GW.OWNER) == (UInt32)_Owner) //If one window is owned by our main window...
            {
                GetClassName(hwnd, sClassname, 255);
                if (sClassname.ToString() == "#32770") //Check if the class is FolderBrowserDialog.
                {
                    break; //Then we found it.
                }
            }
            hwnd = (System.IntPtr)GetWindow(hwnd, (UInt32)GW.HWNDNEXT); //Next window.
        } //If no found then exit.
        if (hwnd == (System.IntPtr)0)
        {
            return;
        }
        IntPtr hChild = (System.IntPtr)0;
        IntPtr hTreeView = (System.IntPtr)0;
        int i = 0;
        do
        {
            i += 1;
            if (i > 1000) //Security to avoid infinite loop.
            {
                return;
            }
            hChild = FindWindowExW(hwnd, hChild, null, null); //Look for children windows of FolderBrowserDialog.
            hTreeView = FindWindowExW(hChild, (System.IntPtr)0, "SysTreeView32", null); //Look for treeview of FolderBrowserDialog.
            Thread.Sleep(5); //delay necessary because FolderBrowserDialog is in construction, then treeview maybe not yet exist.
        } while (hTreeView == (System.IntPtr)0);
        if (SendMessageW(hwnd, 0x46A, 1, FB.SelectedPath) == (System.IntPtr)0) //Send message BFFM_SETEXPANDED to FolderBrowserDialog.
        {
            SendMessageW(hTreeView, 0x7, 0, null); //Send message WM_SETFOCUS to the treeeview.
        }
    }

Testé cela et cela fonctionne bien. Assurez-vous de bien référencer System.Runtime.InteropServices, System.Threading, System.Threading.Tasks.

0
MC9000

ça marche pour moi

folderBrowserDialog1.Reset();  
folderBrowserDialog1.RootFolder = Environment.SpecialFolder.MyComputer;
folderBrowserDialog1.SelectedPath = WorkingFolder;

mais seulement après la deuxième utilisation du dialogue

0
oferb