.net - net - ¿Cómo configura un OpenFileDialog para seleccionar carpetas?
openfiledialog vb net (17)
En VS .NET, cuando selecciona una carpeta para un proyecto, se muestra un cuadro de diálogo que se parece a OpenFileDialog o SaveFileDialog, pero está configurado para aceptar solo carpetas. Desde que he visto esto, he querido saber cómo se hace. Soy consciente del FolderBrowserDialog, pero nunca me ha gustado ese diálogo. Comienza demasiado pequeño y no me permite aprovechar la posibilidad de escribir una ruta.
Ya casi estoy seguro de que no hay una forma de hacer esto desde .NET, pero tengo la misma curiosidad de cómo hacerlo también desde un código no administrado. Aparte de reimplementar completamente el diálogo desde cero, ¿cómo se modifica el diálogo para tener este comportamiento?
También me gustaría reiterar que soy consciente del FolderBrowserDialog pero a veces no me gusta usarlo, además de ser realmente curioso sobre cómo configurar un diálogo de esta manera. Decirme que solo use el 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 una cosa específica de Vista; He estado viendo este cuadro de diálogo desde VS.NET 2003, por lo que es factible en Win2k y WinXP. Esto es menos de una pregunta de "Quiero saber la forma correcta de hacer esto" y más de una pregunta "Tengo curiosidad acerca de esto desde la primera vez que quise hacerlo en VS 2003". Entiendo que el cuadro de diálogo de archivos de Vista tiene una opción para hacer esto, pero ha estado trabajando en XP, así que sé que hicieron algo para que funcionara. Las respuestas específicas de Vista no son respuestas, porque Vista no existe en el contexto de la pregunta.
Actualización: Estoy aceptando la respuesta de Scott Wisniewski porque viene con una muestra de trabajo, pero creo que Serge merece crédito por señalar la personalización del diálogo (que es ciertamente desagradable de .NET pero funciona) y Mark Ransom por descubrir que MS Probablemente rodó un diálogo personalizado para esta tarea.
Bien, déjame intentar conectar el primer punto ;-) Jugar un poco con Spy ++ o Winspector muestra que el cuadro de texto Carpeta en la ubicación del proyecto VS es una personalización del cuadro de 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 que se encuentra en el Bloc de notas.
A partir de ahí, me imagino que VS oculta los cuadros de texto / tipos de archivo de tipo de archivo y tipo de archivo y utiliza una plantilla de diálogo personalizada para agregar su propia parte en la parte inferior del cuadro de diálogo.
EDITAR: Aquí hay un ejemplo de dicha personalización y cómo hacerlo (en Win32. No .NET):
m_ofn es la estructura OPENFILENAME que subyace en el cuadro de 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 cuadro de diálogo. Vea la parte en rojo a continuación. texto alternativo http://apptranslator.com/_so/customizedfiledialog.png
En este caso, la parte personalizada es solo una etiqueta + un hipervínculo, pero podría ser cualquier diálogo. Podría contener un botón Aceptar que nos permitiría validar la selección de la carpeta solamente.
Pero no sé cómo nos desharíamos de algunos de los controles en la parte estándar del diálogo.
Más detalles en este artículo de MSDN .
Después de horas de búsqueda, encontré esta respuesta de leetNightShade en una solución funcional .
Hay tres cosas que creo que hacen que esta solución sea mucho mejor que todas las demás.
- Es simple de usar. Solo requiere que incluyas dos archivos (que pueden combinarse en uno solo) en tu proyecto.
- Se FolderBrowserDialog al FolderBrowserDialog estándar cuando se usa en XP o sistemas más antiguos.
- El autor otorga permiso para utilizar el código para cualquier propósito que considere oportuno.
No existe una licencia como tal, ya que puede tomar y hacer con el código lo que quiera.
Descarga el código aquí .
El paquete Ookii.Dialogs contiene un contenedor administrado alrededor del nuevo cuadro de diálogo del navegador de carpetas (estilo Vista). También se degrada con gracia en sistemas operativos más antiguos.
En Vista, puede usar IFileDialog con la opción FOS_PICKFOLDERS establecida. Eso hará 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 antiguos, siempre puedes recurrir al truco seleccionando cualquier archivo en la carpeta.
here puede encontrar un ejemplo de trabajo que funciona en .NET Framework 2.0 y versiones posteriores.
Existe el paquete de código API de Windows. Tiene muchas cosas relacionadas con el shell, incluida la clase CommonOpenFileDialog
(en el espacio de nombres Microsoft.WindowsAPICodePack.Dialogs
). Esta es la solución perfecta: el diálogo de apertura habitual con solo las carpetas mostradas.
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 no oficiales a NuGet. Un ejemplo se puede encontrar here . Este paquete es sólo el material específico del shell. Si lo necesita, el mismo usuario tiene varios otros paquetes que ofrecen más funcionalidad presente en el paquete original.
La biblioteca Ookii Dialogs for WPF tiene una clase que proporciona una implementación de un cuadro de diálogo del navegador de carpetas para WPF.
También hay una versión que funciona con Windows Forms .
Mejor usar el FolderBrowserDialog para eso.
using (FolderBrowserDialog dlg = new FolderBrowserDialog())
{
dlg.Description = "Select a folder";
if (dlg.ShowDialog() == DialogResult.OK)
{
MessageBox.Show("You selected: " + dlg.SelectedPath);
}
}
Prueba este de Codeproject (crédito a Nitron):
Creo que es el mismo diálogo del que hablas. ¿Tal vez sería de ayuda si agregas 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;
}
Puede subclasificar el diálogo de 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 esconderlos, recibir mensajes de ellos sobre cambios de selección, etc. Todo depende del esfuerzo que desee realizar.
Hicimos el nuestro utilizando el soporte de clase WTL y personalizamos el diálogo de archivo para incluir una barra de lugares personalizada y vistas COM de plug-in.
MSDN proporciona información sobre cómo hacer esto con Win32, este artículo de CodeProject incluye un ejemplo y este artículo de CodeProject proporciona un ejemplo de .NET .
Puede usar FolderBrowserDialogEx , un derivado reutilizable del FolderBrowserDialog incorporado. Este 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 MS-Public.
Código para utilizarlo:
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;
}
Puedes usar código como este
El filtro es una cadena vacía. El nombre del archivo es AnyName pero no en blanco
openFileDialog.FileName = "AnyFile";
openFileDialog.Filter = string.Empty;
openFileDialog.CheckFileExists = false;
openFileDialog.CheckPathExists = false;
Puedes usar código como este
- El filtro es ocultar archivos.
- El nombre del archivo es ocultar primer texto
Para ocultar de forma avanzada el cuadro de texto para el nombre de archivo, debe consultar OpenFileDialogEx
El código:
{
openFileDialog2.FileName = "/r";
openFileDialog1.Filter = "folders|*.neverseenthisfile";
openFileDialog1.CheckFileExists = false;
openFileDialog1.CheckPathExists = false;
}
Sé que la pregunta era sobre la configuración de OpenFileDialog
pero al ver que Google me trajo aquí, también puedo señalar que si SOLO está buscando carpetas, debería usar un FolderBrowserDialog
como respuesta a otra pregunta SO a continuación.
¿Cómo especificar la ruta usando el diálogo de abrir archivo en vb.net?
Supongo que estás en Vista usando VS2008? En ese caso, creo que la opción FOS_PICKFOLDERS se está utilizando al llamar al diálogo de archivos de Vista IFileDialog . Me temo que en el código .NET esto implicaría un montón de código de interoperabilidad P / Invoke para trabajar.
Tengo un cuadro de diálogo que escribí llamado un cuadro de diálogo OpenFileOrFolder que le permite abrir una carpeta o un archivo.
Si establece el valor de AcceptFiles en falso, entonces solo funciona en el modo de aceptar carpeta.
Exact Audio Copy funciona de esta manera en Windows XP. Se muestra el cuadro de diálogo de abrir archivo estándar, pero el campo de nombre de archivo contiene el texto "Se ignorará el nombre de archivo".
Solo adivinando aquí, pero sospecho que la cadena se inyecta en el control de edición del cuadro de combo cada vez que se realiza un cambio significativo en el diálogo. Mientras el campo no esté en blanco, y los indicadores de diálogo estén configurados para no verificar la existencia del archivo, el diálogo se puede cerrar normalmente.
Edición: esto es mucho más fácil de lo que pensaba. Aquí está el código en C ++ / MFC, puede traducirlo al entorno de su elección.
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 tengo fluidez en C #, así que no me dispares 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, examiné el diálogo real en cuestión, en Visual Studio 2005 (no tuve acceso a él anteriormente). ¡No es el diálogo estándar de 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 clase no coinciden. Cuando mira de cerca, también puede detectar algunas diferencias entre los contenidos de los diálogos. Mi conclusión es que Microsoft reemplazó completamente el diálogo estándar en Visual Studio para darle esta capacidad. Mi solución o algo similar será lo más cercano posible, a menos que esté dispuesto a codificar su propia cuenta desde cero.
Primera solucion
Desarrollé esto como una versión limpia de .NET Win 7-style folder select dialog por Bill Seddon de lyquidity.com (no tengo afiliación). (Aprendí de su código por otra respuesta en esta página ). Escribí la mía porque su solución requiere una clase de Reflexión adicional que no es necesaria para este propósito enfocado, usa el control de flujo basado en excepciones, no almacena en caché los resultados de sus llamadas de reflexión. Tenga en cuenta que la clase VistaDialog
estática anidada es para que sus variables de reflexión estática no intenten completarse si nunca se llama al método Show
. Vuelve al diálogo de pre-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 como tal 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 de estilo Vista.
Segunda solucion
Simon Mourier dio una respuesta que muestra cómo hacer exactamente el mismo trabajo utilizando la interoperabilidad con la API de Windows directamente, aunque su versión tendría que complementarse para usar el cuadro de diálogo de estilo más antiguo si se encuentra en una versión anterior de Windows. Desafortunadamente, no había encontrado su publicación aún cuando elaboré mi solución. Nombre tu veneno!