【问题标题】:FolderBrowser with textbox in VB.NETVB.NET 中带有文本框的文件夹浏览器
【发布时间】:2013-04-08 20:19:18
【问题描述】:

我有一个文本框,其中填充了从数据库获取的路径(但这无关紧要)。所以我想有一个 FolderBrowserDialog 按钮,我在其中打开 - >浏览文件夹并选择一个路径(即通过选择某个文件夹),然后确定/保存这个路径并在文本框中更新它。

所以在整个情况下 - 我不知道如何使用 OpenFolderBrowserDialog,因为当我拖动它时 - 它只进入页面底部,但我想将它作为按钮放在某个位置我的 WinForm。 还有 - 所选路径如何保存到(即字符串)变量中,以便我可以将其设置为文本框的值?某种方法?

【问题讨论】:

  • @Chad - 我相信这个答案在 C# 中有一个等效代码(FolderBrowser2):stackoverflow.com/a/15386992/403671
  • Simon Mourier 对 Shell 接口和函数的定义以 C# 风格和符号为目标,比在线转换器做得更好。如果您使用的转换器已将 ref 关键字按原样转换为 C#,请将全部更改为 out,除非还有 [In] 参数(通常是 Guid)。不需要<MethodImpl> 装饰,因为几乎所有的unmanaged 编组,字符串除外,因为在方法调用中编组它们可能比在之后使用Marshal.PtrToStringAuto(string) 更好。
  • @Chad 您在 Simons Mourier 的答案中找到的接口定义是部分的,而在这里它是完整的(并且也是正确的,尽管 VB.Net 风格),所以您可能想要集成该代码中缺少的内容,遵循相同的模式 - 请注意,指定 FOS_ALLOWMULTISELECT 而不是 FOS_PICKFOLDERS(与您在此处看到的代码相关),您有一个 FileDialog 允许选择文件和目录。实施起来有些困难,但可能值得。
  • @jimi - 这是故意的,这并不意味着它不起作用。需要什么“缺失”?
  • @Simon Mourier 需要什么“缺失”? 在这个有限的用例中,什么都没有。如果 Chad 只是在寻找 C# 翻译,那么这就是所需要的。但是,在保持部分实现方面没有真正的目的,没有任何优势。由于我知道 Shell 接口(你可以用它们做什么)会变得非常上瘾IShellItem/IShellItem2 是导致上瘾的主要因素),Chad 可能想要完成实现,应该好奇心接管。无论如何,我的 cmets 都是简单的信息,关于 FOS_ALLOWMULTISELECT 的注释也是如此。

标签: vb.net textbox folderbrowserdialog


【解决方案1】:

这是一个更好的版本。将此代码放入模块中

Imports System
Imports System.IO
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Public Class OpenFolderDialog
    Implements IDisposable

    ''' <summary>
    ''' Gets/sets folder in which dialog will be open.
    ''' </summary>
    Public Property InitialFolder() As String
        Get
            Return m_InitialFolder
        End Get
        Set(ByVal value As String)
            m_InitialFolder = value
        End Set
    End Property
    Private m_InitialFolder As String

    ''' <summary>
    ''' Gets/sets directory in which dialog will be open if there is no recent directory available.
    ''' </summary>
    Public Property DefaultFolder() As String
        Get
            Return m_DefaultFolder
        End Get
        Set(ByVal value As String)
            m_DefaultFolder = value
        End Set
    End Property
    Private m_DefaultFolder As String

    ''' <summary>
    ''' Gets selected folder.
    ''' </summary>
    Public Property Folder() As String
        Get
            Return m_Folder
        End Get
        Private Set(ByVal value As String)
            m_Folder = value
        End Set
    End Property
    Private m_Folder As String


    Public Function ShowDialog(ByVal owner As IWin32Window) As DialogResult
        If Environment.OSVersion.Version.Major >= 6 Then
            Return ShowVistaDialog(owner)
        Else
            Return ShowLegacyDialog(owner)
        End If
    End Function

    Private Function ShowVistaDialog(ByVal owner As IWin32Window) As DialogResult
        Dim frm = DirectCast(New NativeMethods.FileOpenDialogRCW(), NativeMethods.IFileDialog)
        Dim options As UInteger
        frm.GetOptions(options)
        options = options Or NativeMethods.FOS_PICKFOLDERS Or NativeMethods.FOS_FORCEFILESYSTEM Or NativeMethods.FOS_NOVALIDATE Or NativeMethods.FOS_NOTESTFILECREATE Or NativeMethods.FOS_DONTADDTORECENT
        frm.SetOptions(options)
        If Me.InitialFolder IsNot Nothing Then
            Dim directoryShellItem As NativeMethods.IShellItem
            Dim riid = New Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")
            'IShellItem
            If NativeMethods.SHCreateItemFromParsingName(Me.InitialFolder, IntPtr.Zero, riid, directoryShellItem) = NativeMethods.S_OK Then
                frm.SetFolder(directoryShellItem)
            End If
        End If
        If Me.DefaultFolder IsNot Nothing Then
            Dim directoryShellItem As NativeMethods.IShellItem
            Dim riid = New Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")
            'IShellItem
            If NativeMethods.SHCreateItemFromParsingName(Me.DefaultFolder, IntPtr.Zero, riid, directoryShellItem) = NativeMethods.S_OK Then
                frm.SetDefaultFolder(directoryShellItem)
            End If
        End If

        If frm.Show(owner.Handle) = NativeMethods.S_OK Then
            Dim shellItem As NativeMethods.IShellItem
            If frm.GetResult(shellItem) = NativeMethods.S_OK Then
                Dim pszString As IntPtr
                If shellItem.GetDisplayName(NativeMethods.SIGDN_FILESYSPATH, pszString) = NativeMethods.S_OK Then
                    If pszString <> IntPtr.Zero Then
                        Try
                            Me.Folder = Marshal.PtrToStringAuto(pszString)
                            Return DialogResult.OK
                        Finally
                            Marshal.FreeCoTaskMem(pszString)
                        End Try
                    End If
                End If
            End If
        End If
        Return DialogResult.Cancel
    End Function

    Private Function ShowLegacyDialog(ByVal owner As IWin32Window) As DialogResult
        Using frm = New SaveFileDialog()
            frm.CheckFileExists = False
            frm.CheckPathExists = True
            frm.CreatePrompt = False
            frm.Filter = "|" & Guid.Empty.ToString()
            frm.FileName = "any"
            If Me.InitialFolder IsNot Nothing Then
                frm.InitialDirectory = Me.InitialFolder
            End If
            frm.OverwritePrompt = False
            frm.Title = "Select Folder"
            frm.ValidateNames = False
            If frm.ShowDialog(owner) = DialogResult.OK Then
                Me.Folder = Path.GetDirectoryName(frm.FileName)
                Return DialogResult.OK
            Else
                Return DialogResult.Cancel
            End If
        End Using
    End Function


    Public Sub Dispose() Implements IDisposable.Dispose
    End Sub
    'just to have possibility of Using statement.
End Class

Friend Module NativeMethods


#Region "Constants"

    Public Const FOS_PICKFOLDERS As UInteger = &H20
    Public Const FOS_FORCEFILESYSTEM As UInteger = &H40
    Public Const FOS_NOVALIDATE As UInteger = &H100
    Public Const FOS_NOTESTFILECREATE As UInteger = &H10000
    Public Const FOS_DONTADDTORECENT As UInteger = &H2000000

    Public Const S_OK As UInteger = &H0

    Public Const SIGDN_FILESYSPATH As UInteger = &H80058000UI

#End Region


#Region "COM"

    <ComImport(), ClassInterface(ClassInterfaceType.None), TypeLibType(TypeLibTypeFlags.FCanCreate), Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")> _
    Friend Class FileOpenDialogRCW
    End Class


    <ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
    Friend Interface IFileDialog
        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        <PreserveSig()> _
        Function Show(<[In](), [Optional]()> ByVal hwndOwner As IntPtr) As UInteger
        'IModalWindow 

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function SetFileTypes(<[In]()> ByVal cFileTypes As UInteger, <[In](), MarshalAs(UnmanagedType.LPArray)> ByVal rgFilterSpec As IntPtr) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function SetFileTypeIndex(<[In]()> ByVal iFileType As UInteger) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function GetFileTypeIndex(ByRef piFileType As UInteger) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function Advise(<[In](), MarshalAs(UnmanagedType.[Interface])> ByVal pfde As IntPtr, ByRef pdwCookie As UInteger) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function Unadvise(<[In]()> ByVal dwCookie As UInteger) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function SetOptions(<[In]()> ByVal fos As UInteger) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function GetOptions(ByRef fos As UInteger) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Sub SetDefaultFolder(<[In](), MarshalAs(UnmanagedType.[Interface])> ByVal psi As IShellItem)

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function SetFolder(<[In](), MarshalAs(UnmanagedType.[Interface])> ByVal psi As IShellItem) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function GetFolder(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function GetCurrentSelection(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function SetFileName(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function GetFileName(<MarshalAs(UnmanagedType.LPWStr)> ByRef pszName As String) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function SetTitle(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszTitle As String) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function SetOkButtonLabel(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszText As String) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function SetFileNameLabel(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszLabel As String) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function GetResult(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function AddPlace(<[In](), MarshalAs(UnmanagedType.[Interface])> ByVal psi As IShellItem, ByVal fdap As UInteger) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function SetDefaultExtension(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszDefaultExtension As String) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function Close(<MarshalAs(UnmanagedType.[Error])> ByVal hr As UInteger) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function SetClientGuid(<[In]()> ByRef guid As Guid) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function ClearClientData() As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function SetFilter(<MarshalAs(UnmanagedType.[Interface])> ByVal pFilter As IntPtr) As UInteger
    End Interface


    <ComImport(), Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
    Friend Interface IShellItem
        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function BindToHandler(<[In]()> ByVal pbc As IntPtr, <[In]()> ByRef rbhid As Guid, <[In]()> ByRef riid As Guid, <Out(), MarshalAs(UnmanagedType.[Interface])> ByRef ppvOut As IntPtr) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function GetParent(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function GetDisplayName(<[In]()> ByVal sigdnName As UInteger, ByRef ppszName As IntPtr) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function GetAttributes(<[In]()> ByVal sfgaoMask As UInteger, ByRef psfgaoAttribs As UInteger) As UInteger

        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
        Function Compare(<[In](), MarshalAs(UnmanagedType.[Interface])> ByVal psi As IShellItem, <[In]()> ByVal hint As UInteger, ByRef piOrder As Integer) As UInteger
    End Interface

#End Region

    <DllImport("shell32.dll", CharSet:=CharSet.Unicode, PreserveSig:=False)> _
     Public Function SHCreateItemFromParsingName( _
         <MarshalAs(UnmanagedType.LPWStr)> ByVal pszPath As String, _
         ByVal pbc As IntPtr, _
         <MarshalAs(UnmanagedType.LPStruct)> ByVal riid As Guid, _
         <MarshalAs(UnmanagedType.Interface, IidParameterIndex:=2)> ByRef ppv As IShellItem) As Integer
    End Function
End Module

这样使用

Using frm = New OpenFolderDialog()
                If frm.ShowDialog(Me) = DialogResult.OK Then
                    MessageBox.Show(Me, frm.Folder)
                End If
            End Using

【讨论】:

  • 你能解释一下为什么这个版本更好吗?还是更高级?
  • @modu 更好,因为它是更好的用户体验。与接受的答案不同,在此答案中使用提供的类将在对话窗口中显示路径栏。这使您可以将目录粘贴到路径栏中并按 Enter 键,然后像使用 OpenFileDialog 类一样继续导航。不过,这个类可以使用一些东西,例如 RootFolder 属性,如 FolderBrowserDialog 包含。
  • @Smith 我似乎无法将其完全转换为 C#。 Telerik 转换器帮助了我大部分的工作,但后来我不得不将 SHCreateItemFromParsingName() 从包含正文更改为简单地以 ; 结尾,并且我不得不从 const 本地成员中删除 static 关键字。最后,我必须分别用值初始化directoryShellItemshellItem(这两个值都需要是nullpszString 需要是new IntPtr())。但是当MyNamespace.NativeMethods() 被调用时,我收到以下错误:
  • A call to PInvoke function 'MyProject!MyNamespace.NativeMethods::SHCreateItemFromParsingName' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.' 我已经按照this answerCallingConvention = CallingConvention.Cdecl 添加到[DllImport()] 属性中,但我仍然收到错误消息。
  • 哦,我忘了提到我必须将extern 添加到SHCreateItemFromParsingName() 定义的修饰符中,因为DllImport 没有它就大喊大叫。关于完全转换的任何想法?
【解决方案2】:

试试下面的方法会对你有所帮助..

在您的Form 中放置Text boxButtonFolderBrowserDialog,如下所示...

然后Double click the buttoncreate Button click Event 在您的代码上,如下所示..

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    If (FolderBrowserDialog1.ShowDialog() = DialogResult.OK) Then
        TextBox1.Text = FolderBrowserDialog1.SelectedPath
    End If
End Sub

然后运行它.. 现在您可以通过单击浏览按钮打开文件夹浏览器对话框..

选择文件夹路径后,路径将分配给文本框

您也可以参考这篇文章以获得完整参考:FolderBrowserDialog

【讨论】:

  • 请注意 ShowDialog() 的返回值。
猜你喜欢
  • 1970-01-01
  • 2014-07-08
  • 1970-01-01
  • 2010-10-21
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
  • 2020-12-31
相关资源
最近更新 更多