258

VS .NETでは、プロジェクトのフォルダーを選択すると、OpenFileDialogまたはSaveFileDialogのようなダイアログが表示されますが、フォルダーのみを受け入れるように設定されています。これを見て以来、私はそれがどのように行われるのか知りたいと思っていました。私はFolderBrowserDialogを知っていますが、そのダイアログが本当に好きだったことはありません。最初は小さすぎて、パスを入力できることを利用できません。

.NETからこれを行う方法は今のところほぼ確実ですが、アンマネージコードからも同様にこれを行う方法に興味があります。ダイアログを最初から完全に再実装する以外に、この動作をするようにダイアログをどのように変更しますか?

また、FolderBrowserDialogを認識していることを言い直したいのですが、この方法でダイアログを構成する方法に本当に興味があることに加えて、それを使用したくない場合もあります。FolderBrowserDialogを使用するように指示すると、一貫したUIエクスペリエンスを維持できますが、好奇心を満たせないため、回答としてカウントされません。

これもVista固有のものではありません。このダイアログはVS.NET2003から表示されているので、Win2kとWinXPで実行できます。これは、「これを行うための適切な方法を知りたい」という質問ではなく、「VS 2003で最初にやりたかったので、これについて興味がありました」という質問です。Vistaのファイルダイアログにこれを行うオプションがあることは理解していますが、XPで機能しているので、Vistaを機能させるために何かをしたことがわかります。Vistaは質問のコンテキストに存在しないため、Vista固有の回答は回答ではありません。

更新:Scott Wisniewskiの回答は動作するサンプルが付属しているので受け入れていますが、Sergeはダイアログのカスタマイズ(.NETからは明らかに厄介ですが、動作します)とMarkRansomがそのMSを理解したことを指摘したことは称賛に値すると思いますおそらく、このタスクのカスタムダイアログをロールバックしました。

4

17 に答える 17

61

私が書いたOpenFileOrFolderダイアログと呼ばれるダイアログがあり、フォルダーまたはファイルのいずれかを開くことができます。

AcceptFiles値をfalseに設定すると、フォルダモードでのみ動作します。

ここからGitHubからソースをダウンロードできます

于 2009-02-05T02:58:25.693 に答える
51

Windows API Code Pack があります。CommonOpenFileDialogクラス(Microsoft.WindowsAPICodePack.Dialogs名前空間内)を含む、多くのシェル関連のものがあります。これは完璧な解決策です。フォルダのみが表示された通常の開いているダイアログです。

使用方法の例を次に示します。

CommonOpenFileDialog cofd = new CommonOpenFileDialog();
cofd.IsFolderPicker = true;
cofd.ShowDialog();

残念ながら、Microsoft はこのパッケージを出荷しなくなりましたが、何人かの人々が非公式にバイナリを NuGet にアップロードしています。一例はここにあります。このパッケージはシェル固有のものです。必要に応じて、同じユーザーが元のパッケージにあるより多くの機能を提供する他のパッケージをいくつか持っています。

于 2011-02-14T23:51:20.837 に答える
49

組み込みのFolderBrowserDialogの再利用可能な派生物であるFolderBrowserDialogExを使用できます。これにより、パス、さらには UNC パスを入力できます。また、それを使用してコンピューターまたはプリンターを参照することもできます。組み込みの FBD と同じように機能しますが、... より優れています。

(編集: このダイアログは、ファイルまたはフォルダーを選択するように設定できることを指摘する必要がありました。)

完全なソース コード (1 つの短い C# モジュール)。無料。MS パブリック ライセンス。

それを使用するコード:

var dlg1 = new Ionic.Utils.FolderBrowserDialogEx();
dlg1.Description = "Select a folder to extract to:";
dlg1.ShowNewFolderButton = true;
dlg1.ShowEditBox = true;
//dlg1.NewStyle = false;
dlg1.SelectedPath = txtExtractDirectory.Text;
dlg1.ShowFullPathInEditBox = true;
dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer;

// Show the FolderBrowserDialog.
DialogResult result = dlg1.ShowDialog();
if (result == DialogResult.OK)
{
    txtExtractDirectory.Text = dlg1.SelectedPath;
}
于 2009-03-09T05:02:26.647 に答える
38

Ookii.Dialogsパッケージには、新しい (Vista スタイルの) フォルダー ブラウザー ダイアログのマネージ ラッパーが含まれています。また、古いオペレーティング システムでは正常に機能が低下します。

于 2009-02-04T12:34:53.737 に答える
28

そのためには、FolderBrowserDialog を使用することをお勧めします。

using (FolderBrowserDialog dlg = new FolderBrowserDialog())
{
    dlg.Description = "Select a folder";
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        MessageBox.Show("You selected: " + dlg.SelectedPath);
    }
}
于 2008-08-27T19:59:17.763 に答える
23

何時間も検索した後、私はleetNightShadeによる作業ソリューションへのこの回答を見つけました。

このソリューションが他のすべてのソリューションよりもはるかに優れていると私が信じている 3 つの点があります。

  1. 使い方は簡単です。 プロジェクトに 2 つのファイル (とにかく 1 つに結合できます) を含める必要があるだけです。
  2. XP 以前のシステムで使用すると、標準のFolderBrowserDialogにフォールバックします。
  3. 作成者は、あなたが適切と考えるあらゆる目的のためにコードを使用する許可を与えます。

    ライセンス自体はありません。コードを自由に取り、コードを使用して何をするかは自由です。

コードはこちらからダウンロードしてください。

于 2013-06-09T15:03:12.667 に答える
18

OK、最初のドットを接続してみます ;-) Spy++ または Winspector で少し遊んでみると、VS Project Location の Folder テキストボックスが標準ダイアログのカスタマイズであることがわかります。これは、メモ帳のような標準のファイル ダイアログのファイル名テキスト ボックスと同じフィールドではありません。

そこから、VSはファイル名とファイルタイプのテキストボックス/コンボボックスを非表示にし、カスタムダイアログテンプレートを使用してダイアログの下部に独自の部分を追加すると思います。

EDIT:これは、そのようなカスタマイズの例とその方法です(.NETではなくWin32で):

m_ofn は、ファイル ダイアログの基礎となる OPENFILENAME 構造体です。次の 2 行を追加します。

  m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEDIALOG_IMPORTXLIFF);
  m_ofn.Flags |= OFN_ENABLETEMPLATE;

IDD_FILEDIALOG_IMPORTXLIFF は、ダイアログの下部に追加されるカスタム ダイアログ テンプレートです。下の赤い部分を見てください。 (出典: apptranslator.com )代替テキスト

この場合、カスタマイズされた部分はラベル + ハイパーリンクのみですが、任意のダイアログにすることができます。フォルダーのみの選択を検証できる [OK] ボタンを含めることができます。

しかし、ダイアログの標準部分にあるいくつかのコントロールをどのように取り除くかはわかりません。

詳細については、この MSDN 記事 を参照してください。

于 2009-02-03T08:02:01.200 に答える
17

Exact Audio Copyは、WindowsXPでこのように機能します。標準のファイルを開くダイアログが表示されますが、ファイル名フィールドには「ファイル名は無視されます」というテキストが含まれています。

ここで推測しますが、ダイアログに大幅な変更が加えられるたびに、文字列がコンボボックスの編集コントロールに挿入されると思います。フィールドが空白でなく、ファイルの存在をチェックしないようにダイアログフラグが設定されている限り、ダイアログは正常に閉じることができます。

編集:これは私が思っていたよりもはるかに簡単です。これがC++/ MFCのコードで、選択した環境に変換できます。

CFileDialog dlg(true, NULL, "Filename will be ignored", OFN_HIDEREADONLY | OFN_NOVALIDATE | OFN_PATHMUSTEXIST | OFN_READONLY, NULL, this);
dlg.DoModal();

編集2:これはC#への翻訳であるはずですが、私はC#に精通していないので、うまくいかない場合は撃たないでください。

OpenFileDialog openFileDialog1 = new OpenFileDialog();

openFileDialog1.FileName = "Filename will be ignored";
openFileDialog1.CheckPathExists = true;
openFileDialog1.ShowReadOnly = false;
openFileDialog1.ReadOnlyChecked = true;
openFileDialog1.CheckFileExists = false;
openFileDialog1.ValidateNames = false;

if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
    // openFileDialog1.FileName should contain the folder and a dummy filename
}

編集3:最後に、Visual Studio 2005で問題の実際のダイアログを確認しました(以前はアクセスできませんでした)。これは標準のファイルを開くダイアログではありません!Spy ++でウィンドウを調べて、開いている標準ファイルと比較すると、構造とクラス名が一致していないことがわかります。よく見ると、ダイアログの内容の違いもわかります。私の結論は、MicrosoftがVisual Studioの標準ダイアログを完全に置き換えて、この機能を提供したということです。私の解決策またはそれに類似したものは、最初から独自のコードを作成する意思がない限り、可能な限り近いものになります。

于 2009-02-04T04:10:22.617 に答える
10

このようなコードを使用できます

  • フィルタはファイルを非表示にします
  • ファイル名は最初のテキストを非表示にします

ファイル名のテキストボックスを高度に非表示にするには、 OpenFileDialogExを確認する必要があります

コード:

{
    openFileDialog2.FileName = "\r";
    openFileDialog1.Filter = "folders|*.neverseenthisfile";
    openFileDialog1.CheckFileExists = false;
    openFileDialog1.CheckPathExists = false;
}
于 2009-02-05T02:09:09.193 に答える
10

ファイル ダイアログをサブクラス化し、そのすべてのコントロールにアクセスできます。それぞれに、そのウィンドウ ハンドルを取得するために使用できる識別子があります。次に、それらを表示および非表示にしたり、選択の変更などに関するメッセージを取得したりできます。すべては、どれだけの労力を必要とするかによって異なります。

私たちは WTL クラス サポートを使用し、ファイル ダイアログをカスタマイズして、カスタム プレース バーとプラグイン COM ビューを含めました。

MSDNは、Win32 を使用してこれを行う方法についての情報を提供します。この CodeProject 記事には例が含まれておりこの CodeProject 記事には .NET の例が含まれています。

于 2009-02-03T22:04:16.133 に答える
5

VS2008を使用してVistaを使用していると思いますか? その場合、Vista のファイル ダイアログIFileDialogを呼び出すときにFOS_PICKFOLDERS オプションが使用されていると思います。残念なことに、.NET コードでは、これを機能させるために、危険な P/Invoke 相互運用コードが大量に必要になります。

于 2008-08-28T01:32:43.280 に答える
3

最初の解決策

これは、 lyquidity.comの Bill Seddon による.NET Win 7 スタイルのフォルダー選択ダイアログのクリーンアップ バージョンとして開発しました(私は何の関係もありません)。(このページの別の回答から彼のコードを知りました)。彼のソリューションには、この焦点を絞った目的には必要のない追加の Reflection クラスが必要であり、例外ベースのフロー制御を使用し、リフレクション呼び出しの結果をキャッシュしないため、私は自分で作成しました。ネストされた静的クラスは、メソッドが呼び出されない場合、その静的リフレクション変数が設定されないようにするためのものであることに注意してください。Windows のバージョンが十分に高くない場合は、Vista 以前のダイアログにフォールバックします。Windows 7、8、9、10 以降で動作するはずです (理論上)。VistaDialogShow

using System;
using System.Reflection;
using System.Windows.Forms;

namespace ErikE.Shuriken {
    /// <summary>
    /// Present the Windows Vista-style open file dialog to select a folder. Fall back for older Windows Versions
    /// </summary>
    public class FolderSelectDialog {
        private string _initialDirectory;
        private string _title;
        private string _fileName = "";

        public string InitialDirectory {
            get { return string.IsNullOrEmpty(_initialDirectory) ? Environment.CurrentDirectory : _initialDirectory; }
            set { _initialDirectory = value; }
        }
        public string Title {
            get { return _title ?? "Select a folder"; }
            set { _title = value; }
        }
        public string FileName { get { return _fileName; } }

        public bool Show() { return Show(IntPtr.Zero); }

        /// <param name="hWndOwner">Handle of the control or window to be the parent of the file dialog</param>
        /// <returns>true if the user clicks OK</returns>
        public bool Show(IntPtr hWndOwner) {
            var result = Environment.OSVersion.Version.Major >= 6
                ? VistaDialog.Show(hWndOwner, InitialDirectory, Title)
                : ShowXpDialog(hWndOwner, InitialDirectory, Title);
            _fileName = result.FileName;
            return result.Result;
        }

        private struct ShowDialogResult {
            public bool Result { get; set; }
            public string FileName { get; set; }
        }

        private static ShowDialogResult ShowXpDialog(IntPtr ownerHandle, string initialDirectory, string title) {
            var folderBrowserDialog = new FolderBrowserDialog {
                Description = title,
                SelectedPath = initialDirectory,
                ShowNewFolderButton = false
            };
            var dialogResult = new ShowDialogResult();
            if (folderBrowserDialog.ShowDialog(new WindowWrapper(ownerHandle)) == DialogResult.OK) {
                dialogResult.Result = true;
                dialogResult.FileName = folderBrowserDialog.SelectedPath;
            }
            return dialogResult;
        }

        private static class VistaDialog {
            private const string c_foldersFilter = "Folders|\n";

            private const BindingFlags c_flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
            private readonly static Assembly s_windowsFormsAssembly = typeof(FileDialog).Assembly;
            private readonly static Type s_iFileDialogType = s_windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog");
            private readonly static MethodInfo s_createVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("CreateVistaDialog", c_flags);
            private readonly static MethodInfo s_onBeforeVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("OnBeforeVistaDialog", c_flags);
            private readonly static MethodInfo s_getOptionsMethodInfo = typeof(FileDialog).GetMethod("GetOptions", c_flags);
            private readonly static MethodInfo s_setOptionsMethodInfo = s_iFileDialogType.GetMethod("SetOptions", c_flags);
            private readonly static uint s_fosPickFoldersBitFlag = (uint) s_windowsFormsAssembly
                .GetType("System.Windows.Forms.FileDialogNative+FOS")
                .GetField("FOS_PICKFOLDERS")
                .GetValue(null);
            private readonly static ConstructorInfo s_vistaDialogEventsConstructorInfo = s_windowsFormsAssembly
                .GetType("System.Windows.Forms.FileDialog+VistaDialogEvents")
                .GetConstructor(c_flags, null, new[] { typeof(FileDialog) }, null);
            private readonly static MethodInfo s_adviseMethodInfo = s_iFileDialogType.GetMethod("Advise");
            private readonly static MethodInfo s_unAdviseMethodInfo = s_iFileDialogType.GetMethod("Unadvise");
            private readonly static MethodInfo s_showMethodInfo = s_iFileDialogType.GetMethod("Show");

            public static ShowDialogResult Show(IntPtr ownerHandle, string initialDirectory, string title) {
                var openFileDialog = new OpenFileDialog {
                    AddExtension = false,
                    CheckFileExists = false,
                    DereferenceLinks = true,
                    Filter = c_foldersFilter,
                    InitialDirectory = initialDirectory,
                    Multiselect = false,
                    Title = title
                };

                var iFileDialog = s_createVistaDialogMethodInfo.Invoke(openFileDialog, new object[] { });
                s_onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, new[] { iFileDialog });
                s_setOptionsMethodInfo.Invoke(iFileDialog, new object[] { (uint) s_getOptionsMethodInfo.Invoke(openFileDialog, new object[] { }) | s_fosPickFoldersBitFlag });
                var adviseParametersWithOutputConnectionToken = new[] { s_vistaDialogEventsConstructorInfo.Invoke(new object[] { openFileDialog }), 0U };
                s_adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken);

                try {
                    int retVal = (int) s_showMethodInfo.Invoke(iFileDialog, new object[] { ownerHandle });
                    return new ShowDialogResult {
                        Result = retVal == 0,
                        FileName = openFileDialog.FileName
                    };
                }
                finally {
                    s_unAdviseMethodInfo.Invoke(iFileDialog, new[] { adviseParametersWithOutputConnectionToken[1] });
                }
            }
        }

        // Wrap an IWin32Window around an IntPtr
        private class WindowWrapper : IWin32Window {
            private readonly IntPtr _handle;
            public WindowWrapper(IntPtr handle) { _handle = handle; }
            public IntPtr Handle { get { return _handle; } }
        }
    }
}

Windows フォームでは次のように使用されます。

var dialog = new FolderSelectDialog {
    InitialDirectory = musicFolderTextBox.Text,
    Title = "Select a folder to import music from"
};
if (dialog.Show(Handle)) {
    musicFolderTextBox.Text = dialog.FileName;
}

もちろん、そのオプションとそれが公開するプロパティをいじることができます。たとえば、Vista スタイルのダイアログで複数選択が可能です。

2 番目のソリューション

Simon Mourier は、Windows API に対して直接相互運用を使用してまったく同じ仕事を行う方法を示す回答を提供しましたが、古いバージョンの Windows では、古いスタイルのダイアログを使用するために彼のバージョンを補足する必要があります。残念ながら、私が解決策を練ったとき、彼の投稿はまだ見つかりませんでした。あなたの毒に名前を付けてください!

于 2015-11-20T21:27:08.000 に答える
1

このようなコードを使用できます

フィルタは空の文字列です。ファイル名は AnyName ですが、空白ではありません

        openFileDialog.FileName = "AnyFile";
        openFileDialog.Filter = string.Empty;
        openFileDialog.CheckFileExists = false;
        openFileDialog.CheckPathExists = false;
于 2012-03-19T02:42:08.123 に答える
1

Vista では、FOS_PICKFOLDERS オプションを設定して IFileDialog を使用できます。これにより、フォルダーを選択できる OpenFileDialog のようなウィンドウが表示されます。

var frm = (IFileDialog)(new FileOpenDialogRCW());
uint options;
frm.GetOptions(out options);
options |= FOS_PICKFOLDERS;
frm.SetOptions(options);

if (frm.Show(owner.Handle) == S_OK) {
    IShellItem shellItem;
    frm.GetResult(out shellItem);
    IntPtr pszString;
    shellItem.GetDisplayName(SIGDN_FILESYSPATH, out pszString);
    this.Folder = Marshal.PtrToStringAuto(pszString);
}

古い W​​indows では、フォルダ内の任意のファイルを選択するというトリックにいつでも頼ることができます。

.NET Framework 2.0 以降で動作する実際の例は、ここにあります。

于 2012-01-04T01:18:33.443 に答える
1

Codeprojectからこれを試してください( Nitronのクレジット):

あなたが話しているのと同じダイアログだと思います-スクリーンショットを追加すると役立つでしょうか?

bool GetFolder(std::string& folderpath, const char* szCaption=NULL, HWND hOwner=NULL)
{
    bool retVal = false;

    // The BROWSEINFO struct tells the shell how it should display the dialog.
    BROWSEINFO bi;
    memset(&bi, 0, sizeof(bi));

    bi.ulFlags   = BIF_USENEWUI;
    bi.hwndOwner = hOwner;
    bi.lpszTitle = szCaption;

    // must call this if using BIF_USENEWUI
    ::OleInitialize(NULL);

    // Show the dialog and get the itemIDList for the selected folder.
    LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi);

    if(pIDL != NULL)
    {
        // Create a buffer to store the path, then get the path.
        char buffer[_MAX_PATH] = {'\0'};
        if(::SHGetPathFromIDList(pIDL, buffer) != 0)
        {
            // Set the string value.
            folderpath = buffer;
            retVal = true;
        }       

        // free the item id list
        CoTaskMemFree(pIDL);
    }

    ::OleUninitialize();

    return retVal;
}
于 2009-02-03T08:39:09.393 に答える