Вопрос

В VS .NET, когда вы выбираете папку для проекта, отображается диалоговое окно, которое выглядит как OpenFileDialog или SaveFileDialog, но настроено на прием только папок.С тех пор как я увидел это, я хотел знать, как это делается.Я знаю о FolderBrowserDialog, но мне никогда по-настоящему не нравился этот диалог.Он начинается слишком маленьким и не позволяет мне воспользоваться возможностью ввода пути.

Я почти уверен, что сейчас нет способа сделать это из .NET, но мне так же любопытно, как вы делаете это и из неуправляемого кода.За исключением полного переопределения диалогового окна с нуля, как вы можете изменить диалоговое окно, чтобы оно имело такое поведение?

Я также хотел бы повторить, что я знаю о FolderBrowserDialog, но иногда мне не нравится им пользоваться, в дополнение к тому, что мне искренне любопытно, как настроить диалоговое окно таким образом.Указание мне просто использовать FolderBrowserDialog помогает мне поддерживать согласованный пользовательский интерфейс, но не удовлетворяет моего любопытства, поэтому это не будет считаться ответом.

Это тоже не относится к Vista конкретно;Я вижу это диалоговое окно с версии .NET 2003, так что оно выполнимо в Win2k и WinXP.Это не столько вопрос типа "Я хочу знать, как правильно это сделать", сколько вопрос типа "Мне было любопытно это с тех пор, как я впервые захотел сделать это в версии 2003".Я понимаю, что в диалоговом окне "Файл" Vista есть опция для этого, но она работала в XP, поэтому я знаю, что они это сделали что - то чтобы заставить это работать.Ответы, относящиеся к Vista, не являются ответами, потому что Vista не существует в контексте вопроса.

Обновить:Я принимаю ответ Скотта Вишневски, потому что он поставляется с рабочим образцом, но я думаю, что Серж заслуживает похвалы за указание на настройку диалогового окна (что, по общему признанию, неприятно из .NET, но это делает work) и отметьте Ransom за то, что выяснили, что MS, вероятно, запустила пользовательский диалог для этой задачи.

Это было полезно?

Решение

У меня есть диалоговое окно, которое я написал под названием OpenFileOrFolder dialog, которое позволяет вам открыть либо папку, либо файл.

Если вы установите для него значение AcceptFiles равным false, то он будет работать только в режиме accept folder.

Вы можете скачать исходный код с GitHub здесь

Другие советы

Существует пакет кода Windows API.В нем есть много всего, связанного с оболочкой, включая CommonOpenFileDialog класс (в Microsoft.WindowsAPICodePack.Dialogs пространство имен).Это идеальное решение - обычное диалоговое окно открытия, в котором отображаются только папки.

Вот пример того, как это использовать:

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

К сожалению, Microsoft больше не поставляет этот пакет, но несколько человек неофициально загрузили двоичные файлы в NuGet.Можно найти один пример здесь.Этот пакет - всего лишь материал, специфичный для оболочки.Если вам это понадобится, у того же пользователя есть несколько других пакетов, которые предлагают больше функциональности, присутствующей в оригинальном пакете.

Вы можете использовать Folderbrowserдиалогекс - производная от встроенного FolderBrowserDialog для многократного использования.Этот позволяет вам ввести путь, даже UNC-путь.С его помощью вы также можете искать компьютеры или принтеры.Работает точно так же, как встроенный FBD, но ...лучше.

(РЕДАКТИРОВАТЬ:Я должен был указать, что это диалоговое окно может быть настроено на выбор файлов или папок.)

Полный исходный код (один короткий модуль 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;
}

Тот Самый Оокии.Диалоги пакет содержит управляемую оболочку для нового диалогового окна браузера папок (в стиле Vista).Он также изящно деградирует в старых операционных системах.

Для этого лучше использовать FolderBrowserDialog.

using (FolderBrowserDialog dlg = new FolderBrowserDialog())
{
    dlg.Description = "Select a folder";
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        MessageBox.Show("You selected: " + dlg.SelectedPath);
    }
}

После нескольких часов поисков я нашел этот ответ Автор: Литнайтшейд Для рабочее решение.

Есть три вещи, которые, по моему мнению, делают это решение намного лучше всех остальных.

  1. Он прост в использовании. Для этого требуется только, чтобы вы включили в свой проект два файла (которые в любом случае могут быть объединены в один).
  2. Это возвращается к стандарту Каталог FolderBrowserDialog при использовании в XP или более старых системах.
  3. Автор дает разрешение использовать код в любых целях, которые вы сочтете подходящими.

    Лицензии как таковой нет, поскольку вы вольны брать и делать с кодом все, что пожелаете.

Загрузите код здесь.

Точная Копия Аудио работает таким образом в Windows XP.Отображается стандартное диалоговое окно открытия файла, но поле имени файла содержит текст "Имя файла будет проигнорировано".

Здесь я просто предполагаю, но я подозреваю, что строка вводится в элемент управления редактированием поля со списком каждый раз, когда в диалоговое окно вносятся существенные изменения.Пока поле не является пустым, а флаги диалогового окна установлены так, чтобы не проверять существование файла, диалоговое окно может быть закрыто в обычном режиме.

Редактировать: это намного проще, чем я думал.Вот код на 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, чтобы предоставить ему эту возможность.Мое решение или что-то подобное будет настолько близко, насколько вы сможете, если только вы не хотите создавать свое собственное с нуля.

Хорошо, давайте я попробую подключить первую точку ;-) Небольшая игра со Spy ++ или Winspector показывает, что текстовое поле папки в расположении проекта VS является настройкой стандартного диалогового окна.Это не то же поле, что текстовое поле имени файла в стандартном диалоговом окне файла, таком как в Блокноте.

С этого момента, я полагаю, VS скрывает текстовые поля / comboboxes имени файла и типа файла и использует пользовательский шаблон диалогового окна для добавления своей собственной части в нижней части диалогового окна.

Редактировать:Вот пример такой настройки и как это сделать (в Win32.не .NET):

m_ofn - это структура OPENFILENAME, которая лежит в основе диалогового окна file.Добавьте эти 2 строки:

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

где IDD_FILEDIALOG_IMPORTXLIFF - это пользовательский шаблон диалогового окна, который будет добавлен в нижней части диалогового окна.Смотрите часть, выделенную красным цветом ниже.alt text
(источник: apptranslator.com)

В этом случае настраиваемая часть представляет собой всего лишь метку + гиперссылку, но это может быть любое диалоговое окно.Он мог бы содержать кнопку OK, которая позволила бы нам подтвердить выбор только папки.

Но как мы могли бы избавиться от некоторых элементов управления в стандартной части диалогового окна, я не знаю.

Более подробно в эта статья MSDN.

Вы можете создать подкласс диалогового окна file и получить доступ ко всем его элементам управления.Каждый из них имеет идентификатор, который может быть использован для получения дескриптора его окна.Затем вы можете показывать и скрывать их, получать от них сообщения об изменениях выбора и т.д.и т.д.Все зависит от того, сколько усилий вы хотите приложить.

Мы сделали наш, используя поддержку класса WTL, и настроили диалоговое окно файла, включив в него панель пользовательских мест и подключаемые COM-представления.

MSDN предоставляет информацию о том, как это сделать с помощью Win32, эта статья CodeProject содержит пример, и в этой статье CodeProject приведен пример .NET.

Вы можете использовать такой код, как этот

  • Фильтр предназначен для скрытия файлов
  • Имя файла - скрыть первый текст

Чтобы дополнительно скрыть текстовое поле для имени файла, вам нужно посмотреть на OpenFileDialogEx - Открытый файловый каталог

Код:

{
    openFileDialog2.FileName = "\r";
    openFileDialog1.Filter = "folders|*.neverseenthisfile";
    openFileDialog1.CheckFileExists = false;
    openFileDialog1.CheckPathExists = false;
}

Я предполагаю, что вы используете Vista, используя VS2008?В таком случае я думаю, что Параметр FOS_PICKFOLDERS используется при вызове диалогового окна Vista file (файл) IFileDialog.Я боюсь, что в .NET-коде это потребовало бы большого количества корявого кода взаимодействия P / Invoke для начала работы.

Первое Решение

Я разработал это как очищенную версию Диалоговое окно выбора папки в стиле .NET Win 7 автор : Билл Седдон из lyquidity.com (У меня нет никакой аффилированности).(Я узнал о его коде из еще один ответ на этой странице).Я написал свое собственное, потому что его решение требует дополнительного класса отражения, который не нужен для этой целенаправленной цели, использует управление потоком на основе исключений, не кэширует результаты своих вызовов отражения.Обратите внимание, что вложенный статический VistaDialog класс устроен так, что его статические переменные отражения не пытаются быть заполненными, если Show метод никогда не вызывается.Он возвращается к диалоговому окну до версии Vista, если не в достаточно высокой версии Windows.Должен работать в Windows 7, 8, 9, 10 и выше (теоретически).

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.

Второе Решение

Симон Мурье дал ответ это показывает, как выполнить точно такую же работу, используя взаимодействие напрямую с Windows API, хотя его версию пришлось бы дополнить, чтобы использовать диалоговое окно старого стиля, если в более старой версии Windows.К сожалению, я еще не нашел его сообщение, когда разрабатывал свое решение.Назови свой яд!

Попробуйте это из Кодпроект (заслуга 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;
}

В Vista вы можете использовать IFileDialog с установленным параметром FOS_PICKFOLDERS.Это вызовет отображение окна, подобного 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);
}

Для старых версий Windows вы всегда можете прибегнуть к хитрости с выбором любого файла в папке.

Рабочий пример, который работает на .NET Framework 2.0 и более поздних версиях, можно найти здесь.

Вы можете использовать такой код, как этот

Фильтр представляет собой пустую строку.Имя файла - AnyName, но не пустое

        openFileDialog.FileName = "AnyFile";
        openFileDialog.Filter = string.Empty;
        openFileDialog.CheckFileExists = false;
        openFileDialog.CheckPathExists = false;

Тот Самый Диалоги Ookii для WPF в библиотеке есть класс, который предоставляет реализацию диалогового окна браузера папок для WPF.

https://github.com/caioproiete/ookii-dialogs-wpf

enter image description here

Существует также версия, которая работает с Формы Windows.

Я знаю, что вопрос был о конфигурации OpenFileDialog но, видя, что Google привел меня сюда, я могу также указать, что если вы ищете ТОЛЬКО папки, вы должны использовать FolderBrowserDialog Вместо этого, как указано в другом вопросе SO ниже

Как указать путь с помощью диалогового окна "Открыть файл" в vb.net?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top