Pregunta

En VS .NET, cuando selecciona una carpeta para un proyecto, se muestra un cuadro de diálogo que parece OpenFileDialog o SaveFileDialog, pero está configurado para aceptar solo carpetas.Desde que vi esto quise saber cómo se hace.Conozco FolderBrowserDialog, pero nunca me ha gustado ese diálogo.Comienza demasiado pequeño y no me deja aprovechar la posibilidad de escribir una ruta.

Estoy casi seguro de que a estas alturas no hay una manera de hacer esto desde .NET, pero también tengo curiosidad por saber cómo hacerlo desde código no administrado.Aparte de reimplementar completamente el diálogo desde cero, ¿cómo se modifica el diálogo para que tenga este comportamiento?

También me gustaría reiterar que conozco FolderBrowserDialog pero a veces no me gusta usarlo, además de tener mucha curiosidad sobre cómo configurar un cuadro de diálogo de esta manera.Decirme que simplemente use FolderBrowserDialog me ayuda a mantener una experiencia de interfaz de usuario consistente, pero no satisface mi curiosidad, por lo que no contará como una respuesta.

Tampoco es algo específico de Vista;He estado viendo este cuadro de diálogo desde VS .NET 2003, por lo que es factible en Win2k y WinXP.Esta es menos una pregunta de "Quiero saber la forma correcta de hacer esto" y más una pregunta de "He sentido curiosidad por esto desde que quise hacerlo por primera vez en VS 2003".Entiendo que el cuadro de diálogo de archivos de Vista tiene una opción para hacer esto, pero ha estado funcionando en XP, así que sé que lo hicieron. algo para que funcione.Las respuestas específicas de Vista no son respuestas porque Vista no existe en el contexto de la pregunta.

Actualizar:Acepto la respuesta de Scott Wisniewski porque viene con una muestra funcional, pero creo que Serge merece crédito por señalar la personalización del diálogo (que ciertamente es desagradable en .NET, pero hace trabajo) y a Mark Ransom por descubrir que MS probablemente lanzó un cuadro de diálogo personalizado para esta tarea.

¿Fue útil?

Solución

Tengo un cuadro de diálogo que escribí llamado cuadro de diálogo OpenFileOrFolder que le permite abrir una carpeta o un archivo.

Si establece su valor AcceptFiles en falso, entonces funciona en modo de aceptar solo carpeta.

Puedes descargar la fuente desde GitHub aquí.

Otros consejos

Existe el paquete de códigos API de Windows.Tiene muchas cosas relacionadas con el shell, incluido el CommonOpenFileDialog clase (en el Microsoft.WindowsAPICodePack.Dialogs espacio de nombres).Esta es la solución perfecta: el habitual cuadro de diálogo abierto en el que sólo se muestran las carpetas.

Aquí hay un ejemplo de cómo usarlo:

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

Desafortunadamente, Microsoft ya no envía este paquete, pero varias personas han subido archivos binarios a NuGet de manera extraoficial.Se puede encontrar un ejemplo aquí.Este paquete es solo el material específico del shell.Si lo necesita, el mismo usuario tiene varios otros paquetes que ofrecen más funciones presentes en el paquete original.

Puedes usar CarpetaNavegadorDialogEx -Una derivada reutilizable de la carpeta incorporada.Éste le permite escribir una ruta, incluso una ruta UNC.También puede buscar computadoras o impresoras con él.Funciona igual que el FBD incorporado, pero...mejor.

(EDITAR:Debería haber señalado que este cuadro de diálogo se puede configurar para seleccionar archivos o carpetas.)

Código fuente completo (un módulo C# corto).Gratis.Licencia pública MS.

Código para usarlo:

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

El Ookii.Diálogos El paquete contiene un contenedor administrado alrededor del nuevo cuadro de diálogo del explorador de carpetas (estilo Vista).También se degrada con gracia en sistemas operativos más antiguos.

Es mejor usar FolderBrowserDialog para eso.

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

Después de horas de búsqueda encontré esta respuesta por leetNocheSombra a una solución de trabajo.

Hay tres cosas que creo que hacen que esta solución sea mucho mejor que todas las demás.

  1. Es simple de usar. Solo requiere que incluyas dos archivos (que de todos modos se pueden combinar en uno) en tu proyecto.
  2. Vuelve al estándar Cuadro de diálogo Explorador de carpetas cuando se utiliza en XP o sistemas más antiguos.
  3. El autor concede permiso para utilizar el código para cualquier fin que considere oportuno.

    No existe una licencia como tal, usted es libre de tomar y hacer con el código lo que quiera.

Descarga el código aquí.

Copia de audio exacta Funciona de esta manera en Windows XP.Se muestra el cuadro de diálogo estándar para abrir archivos, pero el campo de nombre de archivo contiene el texto "El nombre de archivo será ignorado".

Solo estoy adivinando, pero sospecho que la cadena se inyecta en el control de edición del cuadro combinado cada vez que se realiza un cambio significativo en el cuadro de diálogo.Siempre que el campo no esté en blanco y los indicadores del cuadro de diálogo estén configurados para no verificar la existencia del archivo, el cuadro de diálogo se puede cerrar normalmente.

Editar: esto es mucho más fácil de lo que pensaba.Aquí está el código en C++/MFC, puede traducirlo al entorno que elija.

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

Edición 2: Esta debería ser la traducción a C#, pero no hablo C# con fluidez, así que no me disparen si no funciona.

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
}

Edición 3: Finalmente miré el cuadro de diálogo real en cuestión, en Visual Studio 2005 (no tenía acceso a él antes). ¡No es el cuadro de diálogo estándar para abrir archivos! Si inspecciona las ventanas en Spy++ y las compara con un archivo estándar abierto, verá que la estructura y los nombres de las clases no coinciden.Cuando miras de cerca, también puedes detectar algunas diferencias entre los contenidos de los cuadros de diálogo.Mi conclusión es que Microsoft reemplazó por completo el cuadro de diálogo estándar en Visual Studio para darle esta capacidad.Mi solución o algo similar será lo más parecido posible, a menos que esté dispuesto a codificar el suyo propio desde cero.

Ok, permítanme intentar conectar el primer punto ;-) Reproducir un poco con Spy ++ o Winspector muestra que el cuadro de texto de la carpeta en la ubicación del proyecto VS es una personalización del diálogo estándar.No es el mismo campo que el cuadro de texto del nombre de archivo en un cuadro de diálogo de archivo estándar como el del Bloc de notas.

A partir de ahí, me imagino, VS oculta los cuadros de texto/cuadros combinados de nombre de archivo y tipo de archivo y usa una plantilla de diálogo personalizada para agregar su propia parte en la parte inferior del diálogo.

EDITAR:A continuación se muestra un ejemplo de dicha personalización y cómo hacerlo (en Win32.no .NET):

m_ofn es la estructura OPENFILENAME que subyace al diálogo del archivo.Añade estas 2 líneas:

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

donde IDD_FILEDIALOG_IMPORTXLIFF es una plantilla de diálogo personalizada que se agregará en la parte inferior del diálogo.Vea la parte en rojo a continuación.alt text
(fuente: apptranslator.com)

En este caso, la parte personalizada es sólo una etiqueta + un hipervínculo pero podría ser cualquier diálogo.Podría contener un botón Aceptar que nos permitiría validar solo la selección de carpeta.

Pero no sé cómo eliminaríamos algunos de los controles en la parte estándar del diálogo.

Más detalle en este artículo de MSDN.

Puede subclasificar el cuadro de diálogo del archivo y obtener acceso a todos sus controles.Cada uno tiene un identificador que se puede utilizar para obtener su identificador de ventana.Luego puede mostrarlos y ocultarlos, recibir mensajes suyos sobre cambios de selección, etc.etc.Todo depende de cuánto esfuerzo quieras hacer.

Hicimos el nuestro usando soporte de clase WTL y personalizamos el cuadro de diálogo del archivo para incluir una barra de lugares personalizados y vistas COM complementarias.

MSDN proporciona información sobre cómo hacer esto usando Win32, este artículo de CodeProject incluye un ejemplo, y este artículo de CodeProject proporciona un ejemplo de .NET.

Puedes usar código como este.

  • El filtro es ocultar archivos.
  • El nombre del archivo es ocultar el primer texto.

Para ocultar de forma avanzada el cuadro de texto del nombre de archivo, debe consultarOpenFileDialogEx

El código:

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

¿Supongo que estás en Vista usando VS2008?En ese caso creo que el Opción FOS_PICKFOLDERS se utiliza al llamar al cuadro de diálogo del archivo de Vista Diálogo IFile.Me temo que en el código .NET esto implicaría una gran cantidad de código de interoperabilidad P/Invoke retorcido para comenzar a funcionar.

Primera solución

Desarrollé esto como una versión limpia de Cuadro de diálogo de selección de carpeta estilo .NET Win 7 por Bill Seddon de liquidez.com (No tengo afiliación).(Me enteré de su código de otra respuesta en esta pagina).Escribí la mía propia porque su solución requiere una clase de Reflexión adicional que no es necesaria para este propósito específico, usa control de flujo basado en excepciones y no almacena en caché los resultados de sus llamadas de reflexión.Tenga en cuenta que la estática anidada VistaDialog clase es para que sus variables de reflexión estáticas no intenten completarse si el Show El método nunca se llama.Vuelve al cuadro de diálogo anterior a Vista si no está en una versión de Windows lo suficientemente alta.Debería funcionar en Windows 7, 8, 9, 10 y superior (teóricamente).

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

Se usa así en un formulario de Windows:

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

Por supuesto, puedes jugar con sus opciones y las propiedades que expone.Por ejemplo, permite la selección múltiple en el cuadro de diálogo estilo Vista.

Segunda solución

Simon Mourier dio una respuesta eso muestra cómo hacer exactamente el mismo trabajo usando la interoperabilidad directamente con la API de Windows, aunque su versión tendría que complementarse para usar el cuadro de diálogo de estilo anterior si se encuentra en una versión anterior de Windows.Desafortunadamente, aún no había encontrado su publicación cuando encontré mi solución.¡Nombra tu veneno!

Prueba este de proyecto de código (crédito a Nitron):

Creo que es el mismo cuadro de diálogo del que estás hablando. ¿Quizás sería útil agregar una captura de pantalla?

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

En Vista puedes usar Diálogo IFile con la opción FOS_PICKFOLDERS configurada.Eso provocará que se muestre una ventana similar a OpenFileDialog donde puede seleccionar carpetas:

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

Para Windows más antiguo, siempre puedes recurrir al truco de seleccionar cualquier archivo en la carpeta.

Se puede encontrar un ejemplo funcional que funciona en .NET Framework 2.0 y versiones posteriores aquí.

Puedes usar código como este.

El filtro es una cadena vacía.El nombre del archivo es AnyName pero no está en blanco.

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

El Diálogos de Ookii para WPF La biblioteca tiene una clase que proporciona una implementación de un cuadro de diálogo del explorador de carpetas para WPF.

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

enter image description here

También hay una versión que funciona con Formularios de Windows.

Sé que la pregunta era sobre la configuración de OpenFileDialog pero viendo que Google me trajo aquí, también puedo señalar que si SÓLO buscas carpetas deberías usar un FolderBrowserDialog En lugar de eso, como responde otra pregunta SO a continuación

¿Cómo especificar la ruta usando el cuadro de diálogo para abrir archivos en vb.net?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top