Pourquoi le dialogue FolderBrowserDialog ne fait pas défiler vers le dossier sélectionné?
Comme le montre cette capture d'écran, le dossier sélectionné n'est pas dans la vue. Il doit être déroulé pour visualiser le dossier sélectionné.
même dialogue affiche le dossier sélectionné visible sur l'ordinateur différent
Je l'ai lancé sur deux ordinateurs ayant windows 7. Il fonctionne correctement sur l'un mais pas sur la 2e. Il ressemble à quelque chose avec des fenêtres environnement plutôt un problème de code? Quelqu'un peut-il suggérer une correction?
il n'y a pas de changement de code. J'ai utilisé des chemins plus longs à partir de disques différents, 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 ();
}
}
14 réponses
Le problème fondamental est une mauvaise décision de conception dans le FolderBrowserDialog
. Tout d'abord, nous devons réaliser que le FolderBrowserDialog
n'est pas un contrôle .NET, mais est plutôt le Common Dialog
et fait partie de Windows. Le concepteur de cette boîte de dialogue a choisi de ne pas envoyer le message TVM_ENSUREVISIBLE
après l'affichage de la boîte de dialogue et la sélection d'un dossier initial. Ce message fait défiler le contrôle TreeView de sorte que l'élément sélectionné soit visible dans la fenêtre.
donc, tout ce que nous devons faire pour corriger cela est d'envoyer la vue sur les arbres qui fait partie du message FolderBrowserDialog
le TVM_ENSUREVISIBLE
et tout sera grand. Droit? Eh bien, pas si vite. C'est en effet la réponse, mais il y a certaines choses dans nos.
-
tout d'abord, parce que le
FolderBrowserDialog
n'est pas vraiment un .NET control, il n'a pas une collection interneControls
. Cela signifie que nous ne pouvons pas simplement trouver et accéder au TreeView contrôle de l'enfant .NET. -
Deuxièmement, les concepteurs de la classe .NET
FolderBrowserDialog
ont décidé de sceau cette classe. Cette décision malheureuse nous empêche d'en dériver et d'Outrepasser le gestionnaire de messages de fenêtre. Si nous avions pu le faire, nous aurions peut-être essayé de poster le messageTVM_ENSUREVISIBLE
lorsque nous avons reçu le messageWM_SHOWWINDOW
dans le gestionnaire de messages. -
la troisième question Est que nous ne pouvons pas envoyer le message
TVM_ENSUREVISIBLE
jusqu'à ce que le contrôle de vue D'arbre existe réellement comme une fenêtre réelle, et il n'existe pas jusqu'à ce que nous appelions la méthodeShowDialog
. Cependant, cette méthode bloque, de sorte que nous n'aurons pas l'occasion de poster notre message Une fois que cette méthode sera appelée.
pour contourner ces problèmes, j'ai créé une classe d'Assistant statique avec une seule méthode qui peut être utilisée pour montrer un FolderBrowserDialog
, et fera défiler vers le dossier sélectionné. Je gère cela en démarrant un court Timer
juste avant d'appeler la méthode ShowDialog
du dialogue, puis en traquant la poignée de la commande TreeView
dans le handler Timer
(c.-à-d. après que le dialogue est affiché) et en envoyant notre message TVM_ENSUREVISIBLE
.
Cette solution n'est pas parfaite car elle dépend d'une connaissance préalable sur la FolderBrowserDialog
. Plus précisément, je trouve l' dialogue utilisant son titre de fenêtre. Ceci rompt avec les installations non-anglaises. Je traque les contrôles de l'enfant dans le dialogue en utilisant leur IDs d'Item de dialogue, plutôt que le texte du titre ou le nom de la classe, parce que je pensais que ce serait plus fiable avec le temps.
ce code a été testé sur Windows 7 (64 bits), et Windows XP.
voici le code:
(Vous pourriez avoir 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;
}
}
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 le RootFolder
il ne fonctionne PAS sur le premier appel, mais sur le 2ème et suivants. Avec elle, il fonctionne toujours.
comme d'autres l'ont fait remarquer, cette défaillance est dépendant du système d'exploitation:
J'utilise Win 7 Pro x64 SP1
je sais que ce fil est très ancien, mais avec les méthodes d'extension, cela peut être ajouté au FolderBrowserDialog.Méthode ShowDialog, puis utilisée à plusieurs reprises si nécessaire.
l'échantillon (ci-dessous) utilise simplement la méthode easy SendKeys (ce que je déteste faire, mais dans ce cas, cela fonctionne bien). Lorsque vous utilisez la méthode SendKeys pour passer au dossier sélectionné dans la boîte de dialogue, si vous déboguez cela dans Visual Studio, alors l'appel SendKeys s'applique à la fenêtre courante, qui serait la fenêtre de VS active. Pour être plus infaillible et pour éviter que la mauvaise fenêtre n'obtienne le message SendKeys, alors la méthode d'extension contiendrait les appels de méthode externes pour envoyer des messages à la fenêtre spécifique similaire à ce que Marc F a posté, mais traduit 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);
}
}
j'ai lu dans différents forums que cela pourrait être dû à RootFolder parce que SelectedPath et RootFolder sont mutuellement exclusifs, ce qui signifie que les deux ne peuvent pas coexister mais avec rootFolder par défaut(.Desktop), il permet, au moins, l'escalade de l'arbre(naviguer le lecteur/dossiers).
cependant, si RootFolder est changé à autre que le bureau, vous ne seriez pas en mesure de naviguer à chemins UNC.
réponse à Hans Passant: J'ai essayé cette Extension de dialogue, qui a TextBox, mais pas de chance.
personnaliser le dialogue Parcourir pour le dossier pour afficher le chemin
sur VB.Net code, il suffit de mettre cette ligne de code juste avant d'afficher la boîte de dialogue.
SendKeys.Send ("{TAB}{TAB}{RIGHT}")
j'ai trouvé que:
- si
.SelectedPath
se termine par"\", le dialogue défilera vers le bas pour rendre le chemin visible. - si
.SelectedPath
ne se termine pas par"\", le chemin est toujours sélectionné, mais n'est pas garanti visible.
j'ai calculé quelque chose en 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, vous pouvez essayer ma solution.
Mon idée est de lancer une tâche asynchrone juste avant de montrer la folderBrowserDialog
.
j'ai trouvé cela moi-même, mais J'ai été inspiré par Brad post. 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 fais pas connaître le C#.
j'ai rencontré le même problème en c++ /mfc. Il a fonctionné pour moi d'utiliser:: PostMessage plutôt que:: SendMessage dans le bffm_initialized callback to place the TVM_ENSUREVISIBLE msg
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;
}
dlgFolder.RootFolder = Environnement.SpecialFolder.DesktopDirectory;
n'est pas la même chose que
dlgFolder.RootFolder = Environnement.SpecialFolder.De bureau;
Quelle est la différence entre SpecialFolder.De bureau et SpecialFolder.DesktopDirectory?
Le fil lié indique qu'en chemin, ils obtiennent le même résultat. Mais ils ne sont pas les mêmes, car l'un est chemin logique, et l'autre est un chemin d'accès physique.
j'ai trouvé que lorsque l'un ou l'autre est assigné au RootFolder de la boîte de dialogue Ouvrir un dossier, le comportement résultant peut être différent.
comme A.RootFolder affectation, certaines versions de windows, comme win7, traiter l'un ou l'autre comme "bureau". C'est-à-dire, vous pouvez voir la sous-entrée "ordinateur", et ouvrez cela pour voir les lettres individuelles de lecteur. Le. SelectedPath est sélectionné, mais le chemin d'accès sélectionné est seulement rendu visible lorsque le chemin logique du bureau est assigné au .RootFolder.
pire, lors de l'utilisation de la boîte de dialogue parcourir le dossier dans win10 pré-publication, Il apparaît que "DesktopDirectory" comme juste cela, le contenu du répertoire de bureau seulement, sans lien du tout au répertoire de bureau logique. Et ne pas énumérer de sous-Articles. Très frustrant si une application écrite pour win7 essaye d'être utilisée avec win10.
Je pense que le problème que L'OP A est qu'ils ont employé le bureau physique comme la racine, alors qu'ils auraient dû employer le bureau logique.
Je n'ai pas d'explication pour expliquer pourquoi les deux machines différentes de L'OP répondent différemment. Je suppose qu'ils ont deux versions différentes du .net framework installé.
le fait que win10 prerelease a la question" coincé sur le bureau " avec la boîte de dialogue parcourir le dossier peut être due à la plus récent. Network framework livré avec win10 prerelease. Malheureusement, je reste ignorant de tous les faits dans cette affaire (win10), comme je ne l'ai pas encore mis à jour.
P. S. j'ai trouvé que win8 connaît aussi le symptôme" coincé sur le bureau":
la solution était de sélectionner l'interface graphique alternative dans win8. Peut-être que quelque chose de similaire peut être fait dans win10 prerelease.
j'ai lu la discussion et les solutions ci-dessus. En particulier Brat Oestreicher m'a mis dans la bonne direction. Essentiellement, nous devons d'abord trouver la commande TreeView dans la boîte de dialogue SHBrowseForFolder
et envoyer à cette fenêtre le message TVM_ENSUREVISIBLE
. Ce qui suit fait ceci 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]= '"151900920"';
SHGetMalloc(&pMalloc);
pMalloc->lpVtbl->Free(pMalloc,pidl); // deallocate item
pMalloc->lpVtbl->Release(pMalloc);
return (TRUE);
}
return (FALSE);
}
merci Beaucoup Gary Esté .
en réponse au post de Marc F-j'ai converti le VB.Net à 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.
}
}
L'a testé et ça marche très bien. Assurez-vous que vous Système de référence.Runtime.InteropServices, System.Threading, un système.Le filetage.Tâches
ce lien a une réponse simple qui a fonctionné pour moi très bien (j'ai windows 8.1
)
cela fonctionne pour moi
folderBrowserDialog1.Reset();
folderBrowserDialog1.RootFolder = Environment.SpecialFolder.MyComputer;
folderBrowserDialog1.SelectedPath = WorkingFolder;
mais seulement après la deuxième utilisation du dialogue
la meilleure approche, au moins la plus fiable est de créer votre propre boîte de dialogue de classe de navigateur. Le problème de défilement des arbres est douloureux depuis de nombreuses années - il ne sera jamais réparé!
si vous savez rendre dans la peinture il n'y a pas beaucoup que vous ne pouvez pas faire.. rapide dans la peinture et bien, c'est une autre histoire.
le premier endroit où je voudrais regarder est le code source open source .Net sur GitHub, dans votre version .Net de choix, pour la classe de dialogue vous êtes qui souhaitent s'améliorer. Vous pouvez être surpris de ce que vous pouvez accomplir avec un peu d'effort et de suivi. Il suffit de dupliquer le contrôle et déboguer au point où l'erreur se produit et patch - that'a ce que Microsoft fait, donc aussi pouvez-vous!
Puisqu'il s'agit d'un vieux fil et en affichant des échantillons peuvent ne jamais être lus. Il serait plus depuis de poster si demandé.
pourtant pour quelqu'un qui cherche à résoudre un tel problème comme avec le défilement de l'arbre à la " prévu" répertoire, voici quelques conseils. Si un problème existe avec un contrôle ou une bibliothèque qui n'a pas de solution immédiate, créez votre propre version, si possible, étendez l'original et corrigez le problème. J'ai tout réorganisé depuis les fenêtres.Forme.Classe de contrôle aux bibliothèques Win32 dans le seul but d'obtenir des résultats prévisibles et précis.
la bonne nouvelle est qu'avec C# il y a beaucoup de contrôle de bas niveau disponible pour atteindre presque n'importe quel objectif raisonnable et le C est en trop.
Dans le passé, j'ai dépensé beaucoup trop d'heures à chercher une solution à un problème où j'avais juste recréé ce qui n'était pas de travailler beaucoup de temps aurait été sauvé.