Warum scrollt der FolderBrowserDialog-Dialog nicht zum ausgewählten Ordner?

Lesezeit: 9 Minuten

Benutzeravatar von Munawar
Munawar

Wie in diesem Screenshot gezeigt, ist der ausgewählte Ordner nicht in der Ansicht. Es muss nach unten gescrollt werden, um den ausgewählten Ordner anzuzeigen.

Geben Sie hier die Bildbeschreibung ein

Derselbe Dialog zeigt den ausgewählten Ordner, der auf einem anderen Computer sichtbar ist

Geben Sie hier die Bildbeschreibung ein

Ich habe es auf zwei Computern mit Windows 7 ausgeführt. Auf einem funktioniert es korrekt, auf dem zweiten jedoch nicht. Es sieht etwas mit der Windows-Umgebung aus, anstatt ein Codeproblem? Kann jemand eine Lösung vorschlagen?

Es gibt keine Codeänderung. 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 ();
            }

        }

  • Ja, es ist ökologisch. Der Dialog ist in Windows implementiert, nicht in Silverlight. Könnte durchaus ein Windows-Fehler sein, ich wette, dass das normalerweise fehlende Textfeld “Ordner” die Hauptursache ist. Ohne sie wäre der Ordner „Issues“ sichtbar. Wenden Sie sich an den Microsoft-Support, wenn Sie dies weiterverfolgen möchten.

    – Hans Passant

    4. August 2011 um 20:05 Uhr

Benutzeravatar von Brad Oestreicher
Brad Östreicher

Das grundlegende Problem ist eine schlechte Designentscheidung in der FolderBrowserDialog. Zuerst müssen wir erkennen, dass die FolderBrowserDialog ist kein .NET-Steuerelement, sondern das Common Dialog und ist Teil von Windows. Der Designer dieses Dialogfelds hat entschieden, das TreeView-Steuerelement nicht zu senden a TVM_ENSUREVISIBLE Nachricht, nachdem das Dialogfeld angezeigt und ein Anfangsordner ausgewählt wurde. Diese Meldung 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, die TreeView zu senden, die Teil der ist FolderBrowserDialog das TVM_ENSUREVISIBLE Nachricht und alles wird großartig. Recht? Nun, nicht so schnell. Dies ist in der Tat die Antwort, aber es stehen uns einige Dinge im Weg.

  • Erstens, weil die FolderBrowserDialog ist nicht wirklich ein .NET-Steuerelement, es hat kein internes Controls Sammlung. Das bedeutet, dass wir das untergeordnete TreeView-Steuerelement nicht einfach von .NET aus finden und darauf zugreifen können.

  • Zweitens die Designer von .NET FolderBrowserDialog Klasse entschied sich dafür Siegel diese Klasse. Diese unglückliche Entscheidung hindert uns daran, davon abzuleiten und den Window-Message-Handler zu überschreiben. Hätten wir das geschafft, hätten wir vielleicht versucht, das zu posten TVM_ENSUREVISIBLE Nachricht, wenn wir die bekommen haben WM_SHOWWINDOW Nachricht im Nachrichtenhandler.

  • Das dritte Problem ist, dass wir die nicht senden können TVM_ENSUREVISIBLE Nachricht, bis das Tree View-Steuerelement tatsächlich als echtes Fenster existiert, und es existiert nicht, bis wir die aufrufen ShowDialog Methode. Diese Methode blockiert jedoch, sodass wir keine Möglichkeit haben, unsere Nachricht zu posten, sobald diese Methode aufgerufen wird.

Um diese Probleme zu umgehen, habe ich eine statische Hilfsklasse mit einer einzigen Methode erstellt, die zum Anzeigen von a verwendet werden kann FolderBrowserDialog, und bewirkt, dass es zum ausgewählten Ordner blättert. Ich schaffe das, indem ich einen Kurzschluss starte Timer kurz vor Aufruf des Dialogs ShowDialog -Methode und dann das Handle der ausfindig machen TreeView Kontrolle im Timer Handler (dh nachdem der Dialog angezeigt wird) und Senden unserer TVM_ENSUREVISIBLE Botschaft.

Diese Lösung ist nicht perfekt, da sie von einigen Vorkenntnissen abhängt FolderBrowserDialog. Insbesondere finde ich den Dialog anhand seines Fenstertitels. Dies wird mit nicht-englischen Installationen brechen. Ich verfolge die untergeordneten Steuerelemente im Dialog anhand ihrer Dialogelement-IDs und nicht des Titeltexts oder Klassennamens, da ich der Meinung war, dass dies im Laufe der Zeit zuverlässiger wäre.

Dieser Code wurde unter Windows 7 (64 Bit) und Windows XP getestet.

Hier ist der Code: (Sie benötigen möglicherweise: 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;
    }
}

  • Dies sollte als Antwort markiert werden. Ich bin gerade auf das gleiche Problem gestoßen, und dieser Code hat perfekt funktioniert. Es ist auch eine sehr detaillierte und gut geschriebene Erklärung.

    – Dan

    2. Juni 2013 um 20:57 Uhr

  • Was sollte das zweite Argument der Methode sein? ShowFolderBrowser ? Das IWin32Window… ?

    – Syspect

    30. Juni 2013 um 14:29 Uhr

  • @Syspect – Das IWin32Window-Argument ist einfach das übergeordnete Formular, von dem aus die Ordnerauswahl gestartet wird. Wenn Sie dies direkt aus Ihrem Formularcode aufrufen, können Sie einfach das Schlüsselwort „this“ als Parameter verwenden. (Technisch gesehen ist ein IWin32Window eigentlich ein Wrapper um das hWnd hinter dem Formular, aber C# verbirgt all die hässlichen Dinge, die damit zu tun haben, vor Ihnen!)

    – Brad Oestreicher

    12. Juli 2013 um 21:32 Uhr

  • Unter Win7 habe ich beobachtet, dass das Scrollen auftrat und dann zurückgesetzt wurde, als Systemordner wie Bibliotheken usw. zum Baum hinzugefügt wurden, nachdem das Dialogfeld anfänglich angezeigt wurde. Das Festlegen eines anfänglichen Intervalls von 1000 ms reichte aus, um dies zu überwinden, obwohl es nur eine weitere Karte obendrauf ist!

    – Jonathan Mitchell

    15. August 2013 um 13:34 Uhr

  • Auf Win10 gibt es, wie @Jonathan Mitchell angemerkt hat, ein Timing-Problem. Einstellung t.Intervall = 100; war genug, um dies auf meiner Maschine zu lösen (länger für langsamere Maschinen?).

    – Avenmore

    2. November 2015 um 10:34 Uhr

Ich weiß, dass dieser Thread VIEL alt ist, aber mit Erweiterungsmethoden kann dies der FolderBrowserDialog.ShowDialog-Methode hinzugefügt und dann bei Bedarf wiederholt verwendet werden.

Das Beispiel (unten) verwendet nur die einfache SendKeys-Methode (die ich hasse, aber in diesem Fall funktioniert sie gut). Wenn Sie die SendKeys-Methode verwenden, um zum ausgewählten Ordner im Dialogfeld zu springen, wenn Sie dies in Visual Studio debuggen, gilt der SendKeys-Aufruf für das aktuelle Fenster, das das aktive VS-Fenster wäre. Um narrensicherer zu sein und zu vermeiden, dass das falsche Fenster die SendKeys-Nachricht erhält, würde die Erweiterungsmethode dann die externen Methodenaufrufe enthalten, 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);
    }
}

  • Dies war für mich auf einem x64 Windows 8-Betriebssystem am hilfreichsten. Ich habe es jedoch erweitert, indem ich die Ausführung der sendkeys in einem Timer_Tick-Ereignis nach 500 Millisekunden hinzugefügt habe, als es in den ausgewählten Ordner verschoben und dann auf das Stammlaufwerk dieses Ordners zurückgesetzt wurde. Eine Verzögerung war also erforderlich.

    – Hynsee

    23. Juni 2017 um 12:58 Uhr

Benutzeravatar von Tobias Knauss
Tobias Knaus

Ich habe einen Workaround von verwendet https://www.daniweb.com/software-development/csharp/threads/300578/folderbrowserdialog-expanding-the-s 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 ();

Es ist nicht der schönste Weg, aber es funktioniert für mich.
Ohne das RootFolder es funktioniert NICHT beim ersten Anruf, aber beim 2. und folgenden. Damit klappt es immer.

Wie andere beobachtet haben, ist dieser Fehler vom Betriebssystem abhängig:
Ich verwende Win 7 Pro x64 SP1

  • Funktioniert bei mir. Es macht Spaß zu lernen, dass die Tastenfolge Tab-Tab-Rechtspfeil zum ausgewählten Verzeichnis scrollt. In C#: SendKeys.Send("{TAB}{TAB}{RIGHT}");

    – Roland

    15. Februar 2016 um 11:44 Uhr

  • “this failure”: Ich nehme an, dass “this” sich auf den SendKeys-Trick bezieht und dass “failure” “feature” sein sollte.

    – Roland

    15. Februar 2016 um 11:46 Uhr

Benutzeravatar von Loi Condes
Loi Condes

Bei VB.Net-Code fügen Sie diese Codezeile einfach direkt vor dem Anzeigen des Dialogfelds ein.

SendKeys.Send ("{TAB}{TAB}{RIGHT}")

das funktioniert bei mir

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

aber erst nach der zweiten Verwendung des Dialogs

Benutzeravatar der Community
Gemeinschaft

Ich habe in verschiedenen Foren gelesen, dass es an RootFolder liegen könnte, da SelectedPath und RootFolder sich gegenseitig ausschließen, das heißt, beide können nicht nebeneinander existieren, aber mit Standard-RootFolder (.Desktop). /Ordner).

Wenn RootFolder jedoch in einen anderen als Desktop geändert wird, können Sie nicht zu UNC-Pfad navigieren.

Antwort an Hans Passant: Ich habe diese Dialogerweiterung ausprobiert, die TextBox hat, aber kein Glück.

Anpassen des Dialogfelds zum Suchen nach Ordnern, um den Pfad anzuzeigen

Benutzeravatar von Jérémie Bertrand
Jérémie Bertrand

Ich habe das gefunden:

  1. Wenn .SelectedPath mit “\” endet, scrollt der Dialog nach unten, um den Pfad sichtbar zu machen.
  2. Wenn .SelectedPath nicht mit “\” endet, ist der Pfad zwar noch ausgewählt, aber nicht unbedingt sichtbar.

  • Entschuldigung: Diese Lösung funktioniert nur halb so oft. Scheint so, als ob im Inneren eine Rennbedingung herrscht. Hinweis: Verzeichnis sollte vorhanden sein.

    – Aleksandr

    20. März 2018 um 6:00 Uhr

  • Ich habe diese Arbeit noch nicht gesehen. Die Auswahl bleibt immer an der Wurzel.

    – Phil Rogers

    24. November 2020 um 8:37 Uhr

1418080cookie-checkWarum scrollt der FolderBrowserDialog-Dialog nicht zum ausgewählten Ordner?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy