Seleziona un file o una cartella dalla stessa finestra di dialogo in .NET
-
06-07-2019 - |
Domanda
Esiste un " facile " modo di selezionare un file o una cartella dalla stessa finestra di dialogo?
In molte app che creo consento sia i file che le cartelle come input. Fino ad ora finisco sempre per creare un interruttore per alternare tra le finestre di dialogo di selezione di file o cartelle o attenermi solo alla funzionalità di trascinamento della selezione.
Dal momento che sembra una cosa così basilare, immagino che sia stato creato prima, ma cercare su Google non ci sono molte informazioni. Quindi sembra che dovrei ricominciare da zero e creare una finestra di dialogo di selezione personalizzata, ma preferisco non introdurre alcun problema reinventando la ruota per un compito così banale.
Qualcuno ha qualche suggerimento o soluzione esistente?
Per mantenere coerente l'interfaccia utente sarebbe bello se è possibile estendere OpenFileDialog (o FolderBrowserDialog).
Soluzione
Tecnicamente, è possibile. La finestra di dialogo della shell utilizzata da FolderBrowseDialog ha la capacità di restituire sia file che cartelle. Sfortunatamente, questa funzionalità non è esposta in .NET. Neanche la riflessione può colpire il flag di opzione richiesto.
Per farlo funzionare, dovresti P / Invocare SHBrowseForFolder () con il flag BIF_BROWSEINCLUDEFILES attivato in BROWSEINFO.ulFlags (valore = 0x4000). Il P / Invoke è grintoso, è meglio copiare e incollare il codice da un'altra fonte o la classe FolderBrowseDialog stessa con l'aiuto di Reflector.
Altri suggerimenti
Sulla base dei suggerimenti precedenti ho trovato del codice funzionante che utilizza la finestra di dialogo Browser cartelle standard nella seguente posizione: http://topic.csdn.net/t/20020703/05/845468.html
La classe per la finestra di dialogo estesa del browser delle cartelle
Imports System
Imports System.Text
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
Public Class DirectoryDialog
Public Structure BROWSEINFO
Public hWndOwner As IntPtr
Public pIDLRoot As Integer
Public pszDisplayName As String
Public lpszTitle As String
Public ulFlags As Integer
Public lpfnCallback As Integer
Public lParam As Integer
Public iImage As Integer
End Structure
Const MAX_PATH As Integer = 260
Public Enum BrowseForTypes As Integer
Computers = 4096
Directories = 1
FilesAndDirectories = 16384
FileSystemAncestors = 8
End Enum
Declare Function CoTaskMemFree Lib "ole32" Alias "CoTaskMemFree" (ByVal hMem As IntPtr) As Integer
Declare Function lstrcat Lib "kernel32" Alias "lstrcat" (ByVal lpString1 As String, ByVal lpString2 As String) As IntPtr
Declare Function SHBrowseForFolder Lib "shell32" Alias "SHBrowseForFolder" (ByRef lpbi As BROWSEINFO) As IntPtr
Declare Function SHGetPathFromIDList Lib "shell32" Alias "SHGetPathFromIDList" (ByVal pidList As IntPtr, ByVal lpBuffer As StringBuilder) As Integer
Protected Function RunDialog(ByVal hWndOwner As IntPtr) As Boolean
Dim udtBI As BROWSEINFO = New BROWSEINFO()
Dim lpIDList As IntPtr
Dim hTitle As GCHandle = GCHandle.Alloc(Title, GCHandleType.Pinned)
udtBI.hWndOwner = hWndOwner
udtBI.lpszTitle = Title
udtBI.ulFlags = BrowseFor
Dim buffer As StringBuilder = New StringBuilder(MAX_PATH)
buffer.Length = MAX_PATH
udtBI.pszDisplayName = buffer.ToString()
lpIDList = SHBrowseForFolder(udtBI)
hTitle.Free()
If lpIDList.ToInt64() <> 0 Then
If BrowseFor = BrowseForTypes.Computers Then
m_Selected = udtBI.pszDisplayName.Trim()
Else
Dim path As StringBuilder = New StringBuilder(MAX_PATH)
SHGetPathFromIDList(lpIDList, path)
m_Selected = path.ToString()
End If
CoTaskMemFree(lpIDList)
Else
Return False
End If
Return True
End Function
Public Function ShowDialog() As DialogResult
Return ShowDialog(Nothing)
End Function
Public Function ShowDialog(ByVal owner As IWin32Window) As DialogResult
Dim handle As IntPtr
If Not owner Is Nothing Then
handle = owner.Handle
Else
handle = IntPtr.Zero
End If
If RunDialog(handle) Then
Return DialogResult.OK
Else
Return DialogResult.Cancel
End If
End Function
Public Property Title() As String
Get
Return m_Title
End Get
Set(ByVal Value As String)
If Value Is DBNull.Value Then
Throw New ArgumentNullException()
End If
m_Title = Value
End Set
End Property
Public ReadOnly Property Selected() As String
Get
Return m_Selected
End Get
End Property
Public Property BrowseFor() As BrowseForTypes
Get
Return m_BrowseFor
End Get
Set(ByVal Value As BrowseForTypes)
m_BrowseFor = Value
End Set
End Property
Private m_BrowseFor As BrowseForTypes = BrowseForTypes.Directories
Private m_Title As String = ""
Private m_Selected As String = ""
Public Sub New()
End Sub
End Class
Il codice per implementare la finestra di dialogo estesa
Sub Button1Click(ByVal sender As Object, ByVal e As EventArgs)
Dim frmd As DirectoryDialog = New DirectoryDialog()
' frmd.BrowseFor = DirectoryDialog.BrowseForTypes.Directories
' frmd.BrowseFor = DirectoryDialog.BrowseForTypes.Computers
frmd.BrowseFor = DirectoryDialog.BrowseForTypes.FilesAndDirectories
frmd.Title = "Select a file or a folder"
If frmd.ShowDialog(Me) = DialogResult.OK Then
MsgBox(frmd.Selected)
End If
End Sub
È possibile utilizzare OpenFileDialog standard per selezionare una cartella. Ecco un articolo in CodeProject che ha dimostrato un modo per farlo ( http: // www. codeproject.com/KB/dialog/OpenFileOrFolderDialog.aspx ).
È stato fatto. Puoi utilizzare FolderBrowserDialogEx - una derivata riutilizzabile di FolderBrowserDialog incorporato. Questo ti consente di digitare un percorso, anche un percorso UNC. Puoi cercare cartelle o file + cartelle. Puoi cercare computer o stampanti con esso. Basato sull'FBD integrato, ma ... meglio. Più flessibile. Se si fa clic su una cartella nella GUI, il percorso viene visualizzato nella casella di testo. Se si digita un percorso, la cartella viene attivata. Molte opzioni mancano nella finestra di dialogo integrata.
Codice sorgente completo. Gratuito. Licenza MS-Public.
Codice per 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;
}
AFAIK, non c'è nulla nel framework .NET che lo fa immediatamente.
Le finestre di dialogo dei file .NET derivano da CommonDialog :
Le classi ereditate sono obbligate a implementare RunDialog invocando ShowDialog per creare un comune specifico la finestra di dialogo. Le classi ereditate possono sovrascrivere HookProc per implementare gancio specifico della finestra di dialogo funzionalità.
Tutte le finestre di dialogo integrate utilizzano le API della shell che corrispondono alla loro azione, PrintDialog, OpenFileDialog, SaveFileDialog, ecc ...
Molto probabilmente dovresti creare manualmente questa funzionalità.
http://www.pinvoke.net/default.aspx/shell32.shbrowseforfolder
ecco il link gerat se cambi in questo esempio
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_SHAREABLE;
per
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_SHAREABLE | BIF_BROWSEINCLUDEFILES;
otterrai ciò che vuoi
Se desideri visualizzare solo tipi di file specifici, i seguenti articolo (con codice sorgente in C #) può aiutarti:
Spiega anche le altre opzioni disponibili per " personalizzazione " la finestra di dialogo FolderBrowser,
questo ti permetterà di selezionare le cartelle usando OpenFileDialog
openFileDialog1.CheckFileExists = false;
openFileDialog1.ValidateNames = false;
I Ookii Dialogs implementano una finestra di dialogo del browser delle cartelle che consente entrambi file o cartelle come input ed è disponibile per Windows Form e WPF.
Ookii.Dialogs.Wpf
Ookii.Dialogs.WinForms