.net FolderBrowser对话框:保持树和文本字段同步
由于WPF在10多年后仍然缺少一个文件夹浏览器对话框,我不想只为这个对话框设置对System.Windows.Forms的引用,我在谷歌上搜索了一下,找到了一个(我一直认为)适合我需要的好的源代码 代码如下: 土特产:.net FolderBrowser对话框:保持树和文本字段同步,.net,wpf,winapi,.net,Wpf,Winapi,由于WPF在10多年后仍然缺少一个文件夹浏览器对话框,我不想只为这个对话框设置对System.Windows.Forms的引用,我在谷歌上搜索了一下,找到了一个(我一直认为)适合我需要的好的源代码 代码如下: 土特产: Class NativeMethods <DllImport("shell32.dll")> Public Shared Function SHCreateShellItem(pidlParent As IntPtr, psfParent As In
Class NativeMethods
<DllImport("shell32.dll")>
Public Shared Function SHCreateShellItem(pidlParent As IntPtr, psfParent As IntPtr, pidl As IntPtr, ByRef ppsi As IShellItem) As Integer
End Function
<DllImport("shell32.dll")>
Public Shared Function SHParseDisplayName(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszPath As String, ByVal bindingContext As IntPtr, <Out()> ByRef pidl As IntPtr, ByVal sfgaoIn As UInteger, <Out()> ByRef sfgaoOut As UInteger) As Integer
End Function
End Class
<ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Friend Interface IShellItem
Sub BindToHandler(<[In], MarshalAs(UnmanagedType.[Interface])> pbc As IntPtr, <[In]> ByRef bhid As Guid, <[In]> ByRef riid As Guid, ByRef ppv As IntPtr)
Sub GetParent(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem)
Sub GetDisplayName(<[In]> sigdnName As SIGDN, <MarshalAs(UnmanagedType.LPWStr)> ByRef ppszName As String)
Sub GetAttributes(<[In]> sfgaoMask As UInteger, ByRef psfgaoAttribs As UInteger)
Sub Compare(<[In], MarshalAs(UnmanagedType.[Interface])> psi As IShellItem, <[In]> hint As UInteger, ByRef piOrder As Integer)
End Interface
<ComImport, Guid("B63EA76D-1F85-456F-A19C-48159EFA858B"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Friend Interface IShellItemArray
Sub BindToHandler(<[In], MarshalAs(UnmanagedType.[Interface])> pbc As IntPtr, <[In]> ByRef rbhid As Guid, <[In]> ByRef riid As Guid, ByRef ppvOut As IntPtr)
Sub GetPropertyStore(<[In]> Flags As Integer, <[In]> ByRef riid As Guid, ByRef ppv As IntPtr)
Sub GetPropertyDescriptionList(<[In], MarshalAs(UnmanagedType.Struct)> ByRef keyType As IntPtr, <[In]> ByRef riid As Guid, ByRef ppv As IntPtr)
Sub GetAttributes(<[In], MarshalAs(UnmanagedType.I4)> dwAttribFlags As IntPtr, <[In]> sfgaoMask As UInteger, ByRef psfgaoAttribs As UInteger)
Sub GetCount(ByRef pdwNumItems As UInteger)
Sub GetItemAt(<[In]> dwIndex As UInteger, <MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem)
Sub EnumItems(<MarshalAs(UnmanagedType.[Interface])> ByRef ppenumShellItems As IntPtr)
End Interface
<ComImport, Guid("d57c7288-d4ad-4768-be02-9d969532d960"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), CoClass(GetType(FileOpenDialog))>
Friend Interface IFileOpenDialog
<PreserveSig>
Function Show(<[In]> parent As IntPtr) As Integer
Sub SetFileTypes(<[In]> cFileTypes As UInteger, <[In], MarshalAs(UnmanagedType.Struct)> ByRef rgFilterSpec As IntPtr)
Sub SetFileTypeIndex(<[In]> iFileType As UInteger)
Sub GetFileTypeIndex(ByRef piFileType As UInteger)
Sub Advise(<[In], MarshalAs(UnmanagedType.[Interface])> pfde As IntPtr, ByRef pdwCookie As UInteger)
Sub Unadvise(<[In]> dwCookie As UInteger)
Sub SetOptions(<[In]> fos As FOS)
Sub GetOptions(ByRef pfos As FOS)
Sub SetDefaultFolder(<[In], MarshalAs(UnmanagedType.[Interface])> psi As IShellItem)
Sub SetFolder(<[In], MarshalAs(UnmanagedType.[Interface])> psi As IShellItem)
Sub GetFolder(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem)
Sub GetCurrentSelection(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem)
Sub SetFileName(<[In], MarshalAs(UnmanagedType.LPWStr)> pszName As String)
Sub GetFileName(<MarshalAs(UnmanagedType.LPWStr)> ByRef pszName As String)
Sub SetTitle(<[In], MarshalAs(UnmanagedType.LPWStr)> pszTitle As String)
Sub SetOkButtonLabel(<[In], MarshalAs(UnmanagedType.LPWStr)> pszText As String)
Sub SetFileNameLabel(<[In], MarshalAs(UnmanagedType.LPWStr)> pszLabel As String)
Sub GetResult(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem)
Sub AddPlace(<[In], MarshalAs(UnmanagedType.[Interface])> psi As IShellItem, fdcp As Object)
Sub SetDefaultExtension(<[In], MarshalAs(UnmanagedType.LPWStr)> pszDefaultExtension As String)
Sub Close(<MarshalAs(UnmanagedType.[Error])> hr As Integer)
Sub SetClientGuid(<[In]> ByRef guid As Guid)
Sub ClearClientData()
Sub SetFilter(<MarshalAs(UnmanagedType.[Interface])> pFilter As IntPtr)
Sub GetResults(<MarshalAs(UnmanagedType.[Interface])> ByRef ppenum As IShellItemArray)
Sub GetSelectedItems(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsai As IShellItemArray)
End Interface
<ComImport, Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7")>
Class FileOpenDialog
End Class
Enum SIGDN As UInteger
DESKTOPABSOLUTEEDITING = &H8004C000UI
DESKTOPABSOLUTEPARSING = &H80028000UI
FILESYSPATH = &H80058000UI
NORMALDISPLAY = 0
PARENTRELATIVE = &H80080001UI
PARENTRELATIVEEDITING = &H80031001UI
PARENTRELATIVEFORADDRESSBAR = &H8007C001UI
PARENTRELATIVEPARSING = &H80018001UI
URL = &H80068000UI
End Enum
<Flags>
Enum FOS
ALLNONSTORAGEITEMS = &H80
ALLOWMULTISELECT = &H200
CREATEPROMPT = &H2000
DEFAULTNOMINIMODE = &H20000000
DONTADDTORECENT = &H2000000
FILEMUSTEXIST = &H1000
FORCEFILESYSTEM = &H40
FORCESHOWHIDDEN = &H10000000
HIDEMRUPLACES = &H20000
HIDEPINNEDPLACES = &H40000
NOCHANGEDIR = 8
NODEREFERENCELINKS = &H100000
NOREADONLYRETURN = &H8000
NOTESTFILECREATE = &H10000
NOVALIDATE = &H100
OVERWRITEPROMPT = 2
PATHMUSTEXIST = &H800
PICKFOLDERS = &H20
SHAREAWARE = &H4000
STRICTFILETYPES = 4
End Enum
…显示文件夹浏览器对话框,对话框顶部的文本字段设置为我的初始文件夹C:\Windows\System32
,但对话框左侧的树视图仅设置为driveC:
。因此,当我想用鼠标选择初始文件夹的子文件夹时,我需要先单击几下导航到初始文件夹,然后才能选择我真正喜欢的文件夹
有没有办法保持对话框的文本字段和树视图同步
我知道有像ookii.dialogs这样的第三方工具,但我想控制大部分代码。如果添加对System.Windows.Forms的引用,那又有什么关系呢?如果安装了.NET Framework,它始终是可用的,因此您不妨使用它。因为它可能会向内存中添加许多额外的库,如果没有必要,我希望避免这种情况
Public NotInheritable Class FolderBrowserDialog
Private _selectedPath As String
Private _selectedElementName As String
Private _selectedPaths As String()
Private _selectedElementNames As String()
Private _allowNonStoragePlaces As Boolean
Private _multiSelect As Boolean
Public Property SelectedPath As String
Get
Return _selectedPath
End Get
Set(ByVal value As String)
_selectedPath = value
End Set
End Property
Public Property SelectedElementName As String
Get
Return _selectedElementName
End Get
Private Set(value As String)
_selectedElementName = value
End Set
End Property
Public Property SelectedPaths As String()
Get
Return _selectedPaths
End Get
Private Set(value As String())
_selectedPaths = value
End Set
End Property
Public Property SelectedElementNames As String()
Get
Return _selectedElementNames
End Get
Private Set(value As String())
_selectedElementNames = value
End Set
End Property
Public Property AllowNonStoragePlaces As Boolean
Get
Return _allowNonStoragePlaces
End Get
Set(ByVal value As Boolean)
_allowNonStoragePlaces = value
End Set
End Property
Public Property MultiSelect As Boolean
Get
Return _multiSelect
End Get
Set(ByVal value As Boolean)
_multiSelect = value
End Set
End Property
Public Function ShowDialog(ByVal owner As Window) As Boolean
Return Me.ShowDialog(If(owner Is Nothing, IntPtr.Zero, New Interop.WindowInteropHelper(owner).Handle))
End Function
Public Function ShowDialog(ByVal owner As IntPtr) As Boolean
Dim dialog As IFileOpenDialog
If (Environment.OSVersion.Version.Major < 6) Then
Throw New InvalidOperationException("The dialog needs at least Windows Vista to work.")
End If
dialog = Me.CreateNativeDialog
Try
Call Me.SetInitialFolder(dialog)
Call Me.SetOptions(dialog)
If (dialog.Show(owner) <> 0) Then
Return False
End If
Call Me.SetDialogResults(dialog)
Return True
Finally
Marshal.ReleaseComObject(dialog)
End Try
End Function
Private Function CreateNativeDialog() As IFileOpenDialog
Return DirectCast(New FileOpenDialog, IFileOpenDialog)
End Function
Private Sub SetInitialFolder(ByVal dialog As IFileOpenDialog)
Dim item As IShellItem = Nothing
Dim idl As IntPtr
Dim atts As UInteger
If Not String.IsNullOrEmpty(Me.SelectedPath) Then
If (NativeMethods.SHParseDisplayName(Me.SelectedPath, IntPtr.Zero, idl, 0, atts) = 0) AndAlso (NativeMethods.SHCreateShellItem(IntPtr.Zero, IntPtr.Zero, idl, item) = 0) Then
dialog.SetDefaultFolder(item)
End If
End If
End Sub
Private Sub SetOptions(ByVal dialog As IFileOpenDialog)
dialog.SetOptions(Me.GetDialogOptions)
End Sub
Private Function GetDialogOptions() As FOS
Dim options As FOS
options = FOS.PICKFOLDERS
If Me.MultiSelect Then
options = options Or FOS.ALLOWMULTISELECT
End If
If Not Me.AllowNonStoragePlaces Then
options = options Or FOS.FORCEFILESYSTEM
End If
Return options
End Function
Private Sub SetDialogResults(ByVal dialog As IFileOpenDialog)
Dim item As IShellItem = Nothing
Dim path As String = Nothing
Dim value As String = Nothing
If Not Me.MultiSelect Then
dialog.GetResult(item)
Call Me.GetPathAndElementName(item, path, value)
Me.SelectedPath = path
Me.SelectedPaths = New String() {path}
Me.SelectedElementName = value
Me.SelectedElementNames = New String() {value}
Else
Dim items As IShellItemArray = Nothing
Dim count As UInteger
dialog.GetResults(items)
items.GetCount(count)
Me.SelectedPaths = New String(count - 1) {}
Me.SelectedElementNames = New String(count - 1) {}
For i As UInteger = 0 To count - 1
items.GetItemAt(i, item)
Call Me.GetPathAndElementName(item, path, value)
Me.SelectedPaths(i) = path
Me.SelectedElementNames(i) = value
Next i
Me.SelectedPath = Nothing
Me.SelectedElementName = Nothing
End If
End Sub
Private Sub GetPathAndElementName(ByVal item As IShellItem, ByRef path As String, ByRef elementName As String)
item.GetDisplayName(SIGDN.PARENTRELATIVEFORADDRESSBAR, elementName)
Try
item.GetDisplayName(SIGDN.FILESYSPATH, path)
Catch ex As ArgumentException When (ex.HResult = -2147024809)
path = Nothing
End Try
End Sub
End Class
Dim dialog As FolderBrowserDialog
dialog = New FolderBrowserDialog
dialog.SelectedPath = "C:\Windows\System32"
If dialog.ShowDialog(Me) Then
MsgBox(String.Join(", ", dialog.SelectedPaths))
End If