Wie in diesem Screenshot gezeigt, befindet sich der ausgewählte Ordner nicht in der Ansicht. Es muss nach unten gescrollt werden, um den ausgewählten Ordner anzuzeigen.
Im selben Dialogfeld wird der ausgewählte Ordner auf einem anderen Computer angezeigt
Ich habe es auf zwei Computern mit Windows 7 ausgeführt. Es funktioniert auf einem Computer korrekt, auf dem zweiten jedoch nicht. Es sieht etwas mit Windows-Umgebung statt ein Code-Problem? Kann jemand eine Lösung vorschlagen?
Es gibt keine Änderung im Code. Ich habe längere Pfade von verschiedenen Laufwerken verwendet, aber die Ergebnisse sind gleich.
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 ();
}
}
c#
c
folderbrowserdialog
Munawar
quelle
quelle
Antworten:
Das grundsätzliche Problem ist eine schlechte Entwurfsentscheidung in der
FolderBrowserDialog
. Zunächst müssen wir erkennen, dass dasFolderBrowserDialog
kein .NET-Steuerelement ist, sondern dasCommon Dialog
und Teil von Windows. Der Designer dieses Dialogfelds hat beschlossen, dem TreeView-Steuerelement keineTVM_ENSUREVISIBLE
Nachricht zu senden , nachdem das Dialogfeld angezeigt und ein erster Ordner ausgewählt wurde. Diese Nachricht bewirkt, dass ein TreeView-Steuerelement einen Bildlauf durchführt, sodass das aktuell ausgewählte Element im Fenster sichtbar ist.Alles, was wir tun müssen, um dies zu beheben, ist das Senden der TreeView, die Teil
FolderBrowserDialog
derTVM_ENSUREVISIBLE
Nachricht ist, und alles wird großartig. Richtig? Na ja, nicht so schnell. Dies ist zwar die Antwort, aber einige Dinge stehen uns im Weg.Erstens, da
FolderBrowserDialog
es sich nicht wirklich um ein .NET-Steuerelement handelt, verfügt es nicht über eine interneControls
Sammlung. Dies bedeutet, dass wir das untergeordnete TreeView-Steuerelement nicht einfach über .NET finden und darauf zugreifen können.Zweitens haben die Designer der .NET-
FolderBrowserDialog
Klasse beschlossen, diese Klasse zu versiegeln . Diese unglückliche Entscheidung hindert uns daran, daraus abzuleiten und den Fenstermeldungshandler zu überschreiben. Wären wir dazu in der Lage gewesen, hätten wir möglicherweise versucht, dieTVM_ENSUREVISIBLE
Nachricht zu veröffentlichen, als wir dieWM_SHOWWINDOW
Nachricht im Nachrichtenhandler erhalten haben.Das dritte Problem ist, dass wir die
TVM_ENSUREVISIBLE
Nachricht erst senden können, wenn das Tree View-Steuerelement tatsächlich als reales Fenster vorhanden ist, und erst, wenn wir dieShowDialog
Methode aufrufen . Diese Methode wird jedoch blockiert, sodass wir nach dem Aufruf dieser Methode keine Möglichkeit haben, unsere Nachricht zu veröffentlichen.Um diese Probleme zu umgehen, habe ich eine statische Hilfsklasse mit einer einzigen Methode erstellt, mit der a angezeigt werden kann
FolderBrowserDialog
, und veranlasst, dass zum ausgewählten Ordner gescrollt wird. Ich schaffe dies, indem ichTimer
kurz vor dem Aufrufen der Dialogmethode einen Kurzstart beginneShowDialog
und dann das Handle desTreeView
Steuerelements imTimer
Handler aufspüre (dh nachdem der Dialog angezeigt wird) und unsereTVM_ENSUREVISIBLE
Nachricht sende .Diese Lösung ist nicht perfekt, da sie von einigen Vorkenntnissen über die abhängt
FolderBrowserDialog
. Insbesondere finde ich den Dialog anhand seines Fenstertitels. Dies wird bei nicht englischen Installationen unterbrochen. Ich verfolge die untergeordneten Steuerelemente im Dialog anhand ihrer Dialog-Element-IDs anstelle des Titeltextes oder des Klassennamens, da ich der Meinung war, dass dies mit der Zeit zuverlässiger sein würde.Dieser Code wurde unter Windows 7 (64 Bit) und Windows XP getestet.
Hier ist der Code: (Möglicherweise müssen:
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; } }
quelle
ShowFolderBrowser
? DieIWin32Window
...?Ich weiß, dass dieser Thread sehr alt ist, aber mit Erweiterungsmethoden kann dieser zur FolderBrowserDialog.ShowDialog-Methode hinzugefügt und bei Bedarf wiederholt verwendet werden.
Das Beispiel (unten) verwendet nur die einfache SendKeys-Methode (was ich nicht gerne mache, aber in diesem Fall funktioniert es gut). Wenn Sie mit der SendKeys-Methode zum ausgewählten Ordner im Dialogfeld springen und dies in Visual Studio debuggen, gilt der SendKeys-Aufruf für das aktuelle Fenster, das das aktive VS-Fenster ist. Um kinderleichter zu sein und zu verhindern, dass das falsche Fenster die SendKeys-Nachricht erhält, enthält die Erweiterungsmethode die externen Methodenaufrufe, um Nachrichten an das spezifische Fenster zu senden, ähnlich dem, was Marc F gepostet hat, aber in C # übersetzt.
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); } }
quelle
Ich habe eine Problemumgehung von https://www.daniweb.com/software-development/csharp/threads/300578/folderbrowserdialog-expanding-the-selected-directory- verwendet.
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 ();
Es ist nicht der schönste Weg, aber es funktioniert für mich.
Ohne das
RootFolder
funktioniert es NICHT beim ersten Anruf, sondern beim zweiten und folgenden. Damit funktioniert es immer.Wie andere festgestellt haben, hängt dieser Fehler vom Betriebssystem ab:
Ich verwende Win 7 Pro x64 SP1
quelle
SendKeys.Send("{TAB}{TAB}{RIGHT}");
Fügen Sie im VB.Net-Code einfach diese Codezeile ein, bevor Sie den Dialog anzeigen.
SendKeys.Send ("{TAB}{TAB}{RIGHT}")
quelle
Ich habe in verschiedenen Foren gelesen, dass es an RootFolder liegen könnte, da SelectedPath und RootFolder sich gegenseitig ausschließen. Das bedeutet, dass beide nicht nebeneinander existieren können, aber mit dem Standard-RootFolder (.Desktop) zumindest das Klettern im Baum (Navigieren auf dem Laufwerk) ermöglicht / Ordner).
Wenn RootFolder jedoch in einen anderen als Desktop geändert wird, können Sie nicht zu UNC-Pfaden navigieren.
Antwort an Hans Passant: Ich habe diese Dialog-Erweiterung mit TextBox ausprobiert, aber kein Glück.
Anpassen des Dialogfelds "Ordner suchen", um den Pfad anzuzeigen
quelle
das funktioniert bei mir
aber erst nach der zweiten Verwendung des Dialogs
quelle
Ich habe das gefunden:
.SelectedPath
mit "\" endet, wird der Dialog nach unten gescrollt, um den Pfad sichtbar zu machen..SelectedPath
nicht mit "\" endet, ist der Pfad weiterhin ausgewählt, aber nicht sichtbar.quelle
Ich habe etwas in VB.NET berechnet, daher wäre es einfach, es in C # umzuwandeln. Ich bin Franzose und ich bin Anfänger in VB. Wie auch immer, Sie können meine Lösung ausprobieren.
Meine Idee ist es, eine asynchrone Aufgabe kurz vor dem Anzeigen der zu starten
folderBrowserDialog
.Ich habe das selbst gefunden, aber ich wurde von Brad Post inspiriert. Hier ist mein 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
Ich warte auf Ihre Vorschläge. Und jemand kann es in C # übersetzen, weil ich C # nicht kenne.
quelle
Ich habe das gleiche Problem in c ++ / mfc. Es hat bei mir funktioniert, :: PostMessage anstelle von :: SendMessage im Rückruf BFFM_INITIALIZED zu verwenden, um die Nachricht TVM_ENSUREVISIBLE zu platzieren
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; }
quelle
Ich habe die obige Diskussion und Lösungen gelesen. Besonders Brat Oestreicher hat mich in die richtige Richtung gebracht. Im Wesentlichen müssen wir zuerst das TreeView-Steuerelement im
SHBrowseForFolder
Dialogfeld finden und diesem Fenster dieTVM_ENSUREVISIBLE
Nachricht senden . Das Folgende macht dies 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); }
Vielen Dank an Gary Beene .
quelle
dlgFolder.RootFolder = Environment.SpecialFolder.DesktopDirectory;
ist nicht dasselbe wie
dlgFolder.RootFolder = Environment.SpecialFolder.Desktop;
Was ist der Unterschied zwischen SpecialFolder.Desktop und SpecialFolder.DesktopDirectory?
Der verknüpfte Thread gibt an, dass sie als Pfad dasselbe Ergebnis erhalten. Sie sind jedoch nicht gleich, da einer ein logischer und der andere ein physischer Pfad ist.
Ich habe festgestellt, dass das resultierende Verhalten unterschiedlich sein kann, wenn einer der beiden dem RootFolder des Dialogfelds zum Öffnen von Ordnern zugewiesen ist.
Als .RootFolder-Zuweisung behandeln einige Windows-Versionen wie win7 eine der beiden Versionen als "Desktop". Das heißt, Sie können den Untereintrag "Computer" sehen und diesen öffnen, um die einzelnen Laufwerksbuchstaben anzuzeigen. Der .SelectedPath wird in beiden Fällen ausgewählt, der ausgewählte Pfad wird jedoch nur sichtbar, wenn der logische Pfad des Desktops dem .RootFolder zugewiesen ist.
Schlimmer noch, wenn Sie das Dialogfeld zum Durchsuchen von Ordnern in der Win10-Vorabversion verwenden, scheint "DesktopDirectory" genau das zu sein, nur der Inhalt des Desktop-Verzeichnisses, ohne jegliche Verknüpfung mit dem logischen Desktop-Verzeichnis. Und keine Unterelemente darunter aufzulisten. Sehr frustrierend, wenn eine für win7 geschriebene App versucht, mit win10 verwendet zu werden.
Ich denke, das Problem des OP ist, dass sie den physischen Desktop als Root verwendet haben, wenn sie den logischen Desktop hätten verwenden sollen.
Ich habe keine Erklärung dafür, warum die beiden verschiedenen Maschinen des OP unterschiedlich reagieren. Ich würde spekulieren, dass zwei verschiedene Versionen des .NET Frameworks installiert sind.
Die Tatsache, dass bei der Win10-Vorabversion das Problem "Auf dem Desktop hängen geblieben" im Dialogfeld "Ordner durchsuchen" auftritt, kann auf das neuere .NET-Framework zurückzuführen sein, das mit der Win10-Vorabversion ausgeliefert wurde. Leider kenne ich alle Fakten in diesem Fall (win10) nicht, da ich sie noch nicht aktualisiert habe.
PS Ich habe festgestellt, dass bei win8 auch das Symptom "Stuck on Desktop" auftritt:
/superuser/869928/windows-8-1-folder-selection-dialog-missing-my-computer-and-sub-items
Die Problemumgehung bestand darin, die alternative GUI in win8 auszuwählen. Vielleicht kann etwas Ähnliches in Win10 Prerelease gemacht werden.
quelle
Als Antwort auf Marc Fs Beitrag habe ich das VB.Net in C # konvertiert.
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. } }
Getestet und es funktioniert gut. Stellen Sie sicher, dass Sie auf System.Runtime.InteropServices, System.Threading und System.Threading.Tasks verweisen
quelle
Dieser Link hat eine einfache Antwort, die für mich gut funktioniert hat (ich habe Windows
8.1
)FolderBrowserDialog: Erweitert das ausgewählte Verzeichnis
quelle
Der beste und zumindest zuverlässigste Ansatz besteht darin, ein eigenes Dialogfeld für die Browserklasse zu erstellen. Das Problem mit dem Scrollen von Bäumen ist seit vielen Jahren ein Problem - es wird niemals behoben werden!
Wenn Sie wissen, wie man in Farbe rendert, können Sie nicht viel tun. Schnell in Farbe gut, das ist eine andere Geschichte.
Der erste Punkt, den ich mir ansehen würde, ist der Open-Source-.Net-Quellcode auf GitHub in Ihrer .Net-Version Ihrer Wahl für die Dialogklasse, die Sie verbessern möchten. Sie werden überrascht sein, was Sie mit ein wenig Aufwand erreichen und durchziehen können. Duplizieren Sie einfach das Steuerelement und debuggen Sie bis zu dem Punkt, an dem der Fehler auftritt, und patchen Sie - das ist es, was Microsoft auch tut!
Da dies ein alter Thread ist und Posting-Beispiele möglicherweise nie gelesen werden. Es würde mehr machen, da zu posten, wenn man gefragt wird.
Für jemanden, der ein Problem wie das Scrollen des Baums zum "erwarteten" Verzeichnis lösen möchte, gibt es hier einige solide Ratschläge. Wenn ein Problem mit einem Steuerelement oder einer Bibliothek vorliegt, für das keine sofortige Lösung gefunden werden kann, erstellen Sie eine eigene Version. Erweitern Sie nach Möglichkeit das Original und patchen Sie das Problem. Ich habe alles von der Windows.Form.Control-Klasse bis zu Win32-Bibliotheken überarbeitet, um vorhersehbare und genaue Ergebnisse zu erhalten.
Die gute Nachricht ist, dass mit C # eine Menge Low-Level-Steuerung verfügbar ist, um fast jedes vernünftige Ziel zu erreichen, und das ist auch C.
In der Vergangenheit habe ich viel zu viele Stunden damit verbracht, nach einer Lösung für ein Problem zu suchen, bei dem, wenn ich gerade neu erstellt hätte, was nicht funktioniert, viel Zeit gespart worden wäre.
quelle