FolderBrowserDialog ダイアログが選択したフォルダーまでスクロールしないのはなぜですか? 質問する

FolderBrowserDialog ダイアログが選択したフォルダーまでスクロールしないのはなぜですか? 質問する

このスクリーンショットに示されているように、選択したフォルダーはビューに表示されません。選択したフォルダーを表示するには、下にスクロールする必要があります。

ここに画像の説明を入力してください

同じダイアログに、選択したフォルダが別のコンピュータに表示される

ここに画像の説明を入力してください

私はこれを、どちらも Windows 7 を搭載した 2 台のコンピューターで実行しました。1 台では正常に動作しますが、2 台目では動作しません。コードの問題ではなく、Windows 環境に問題があるようです。修正方法を提案してくれる人はいますか?

コードに変更はありません。異なるドライブからのより長いパスを使用しましたが、結果は同じです。

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 ();
            }

        }

ベストアンサー1

根本的な問題は、 の設計上の決定が不適切であることですFolderBrowserDialog。まず、 はFolderBrowserDialog.NET コントロールではなく、 であり、Common DialogWindows の一部であることを認識する必要があります。このダイアログの設計者は、ダイアログが表示されて最初のフォルダが選択された後、TreeView コントロールにメッセージを送信しないことを選択しましTVM_ENSUREVISIBLEた。このメッセージにより、TreeView コントロールがスクロールされ、現在選択されている項目がウィンドウに表示されます。

FolderBrowserDialogしたがって、この問題を解決するには、メッセージの一部である TreeView を送信するだけでTVM_ENSUREVISIBLE、すべてうまくいきます。そうですよね? まあ、そんなに早くは行きません。確かにこれは答えですが、いくつか問題があります。

  • まず、 はFolderBrowserDialog実際には .NET コントロールではないため、内部コレクションがありませんControls。つまり、.NET から TreeView 子コントロールを検索してアクセスすることはできません。

  • 第二に、.NETFolderBrowserDialogクラスの設計者は、シールこのクラス。この残念な決定により、このクラスから派生してウィンドウ メッセージ ハンドラーをオーバーライドすることができなくなりました。これが可能であれば、メッセージ ハンドラーでメッセージTVM_ENSUREVISIBLEを受け取ったときにメッセージを投稿しようとしたかもしれませんWM_SHOWWINDOW

  • TVM_ENSUREVISIBLE3 番目の問題は、ツリー ビュー コントロールが実際のウィンドウとして実際に存在するまでメッセージを送信できず、ShowDialogメソッドを呼び出すまで存在しないことです。ただし、このメソッドはブロックされるため、このメソッドが呼び出されると、メッセージを投稿する機会がなくなります。

これらの問題を回避するために、 を表示するために使用できる単一のメソッドを持つ静的ヘルパー クラスを作成しFolderBrowserDialog、選択したフォルダーまでスクロールさせます。Timerダイアログのメソッドを呼び出す直前にショートを開始し、ハンドラーでコントロールShowDialogのハンドルを追跡して(つまり、ダイアログが表示された後)、メッセージを送信することでこれを実現します。TreeViewTimerTVM_ENSUREVISIBLE

このソリューションは、 に関する事前の知識に依存するため、完璧ではありません。FolderBrowserDialog具体的には、ウィンドウ タイトルを使用してダイアログを検索します。これは、英語以外のインストールでは機能しません。タイトル テキストやクラス名ではなく、ダイアログ項目 ID を使用してダイアログ内の子コントロールを追跡します。これは、時間の経過とともに信頼性が高くなると感じたためです。

このコードは、Windows 7 (64 ビット) および Windows XP でテストされています。

コードは次のとおりです: (次のものが必要になる場合があります: 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;
    }
}

おすすめ記事