从.NET中的同一对话框中选择文件或文件夹

问题描述 投票:31回答:10

是否有“简单”的方法从同一对话框中选择文件或文件夹?

在我创建的许多应用程序中,我允许将文件或文件夹作为输入。到目前为止,我总是最终创建一个开关,在文件或文件夹选择对话框之间切换,或者只使用拖放功能。

因为这似乎是一个基本的东西我想象之前已经创建过,但谷歌搜索不会产生太多信息。因此看起来我需要从头开始创建一个自定义选择对话框,但我宁愿不通过重新发明轮子来执行这样一个简单的任务来引入任何问题。

有人提示或现有解决方案吗?

为了保持UI的一致性,如果可以扩展OpenFileDialog(或FolderBrowserDialog),那将是很好的。

c# .net vb.net winforms openfiledialog
10个回答
12
投票

从技术上讲,这是可能的。 FolderBrowseDialog使用的shell对话框能够返回文件和文件夹。不幸的是,该功能未在.NET中公开。甚至反射都不能戳戳所需的选项标志。

为了使它工作,你必须在BROWSEINFO.ulFlags(值= 0x4000)中打开BIF_BROWSEINCLUDEFILES标志来P / Invoke SHBrowseForFolder()。 P / Invoke是坚韧不拔的,最好使用Reflector的帮助从another source或FolderBrowseDialog类本身复制和粘贴代码。


0
投票

Ookii Dialogs实现了一个文件夹浏览器对话框,允许将文件或文件夹作为输入,并且可用于Windows窗体和WPF。

enter image description here

Ookii.Dialogs.Wpf

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


Ookii.Dialogs.WinForms

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


7
投票

基于以上提示,我找到了一些使用标准文件夹浏览器对话框的工作代码:http://topic.csdn.net/t/20020703/05/845468.html

扩展文件夹浏览器对话框的类

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 

实现扩展对话框的代码

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

5
投票

您可以使用标准OpenFileDialog来选择文件夹。这是CodeProject中的一篇文章,展示了一种方法(http://www.codeproject.com/KB/dialog/OpenFileOrFolderDialog.aspx)。


5
投票

它已经完成了。您可以使用FolderBrowserDialogEx - 内置FolderBrowserDialog的可重用衍生物。这个允许您输入路径,甚至是UNC路径。您可以浏览文件夹或文件+文件夹。您可以使用它浏览计算机或打印机。基于内置的FBD,但......更好。更灵活。如果单击GUI中的文件夹,则路径将显示在文本框中。如果您键入路径,该文件夹将被激活。内置对话框缺少许多选项。

完整源代码。自由。 MS-Public许可证。

FolderBrowserDialogEx

使用它的代码:

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

1
投票

AFAIK,.NET框架中没有任何东西能够开箱即用。

.NET文件对话框派生自CommonDialog

通过调用ShowDialog创建特定的公共对话框,需要继承类来实现RunDialog。继承的类可以覆盖HookProc以实现特定的对话框挂钩功能。


1
投票

所有内置对话框都使用与其动作,PrintDialog,OpenFileDialog,SaveFileDialog等对应的shell API。

您很可能必须手动构建此功能。


1
投票

http://www.pinvoke.net/default.aspx/shell32.shbrowseforfolder

如果您更改此示例,这里是gerat链接

  bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_SHAREABLE;

对于

  bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_SHAREABLE | BIF_BROWSEINCLUDEFILES;

你会得到你想要的


0
投票

如果您只想显示特定的文件类型,以下article(包含C#中的源代码)可以帮助您:

http://www.codeproject.com/KB/shell/csdoesshell1.aspx?fid=14137&df=90&mpp=25&noise=3&sort=Position&view=Quick&fr=26

它还解释了可用于“自定义”FolderBrowser对话框的其他选项,


0
投票

这将允许您使用OpenFileDialog选择文件夹

        openFileDialog1.CheckFileExists = false;
        openFileDialog1.ValidateNames = false;
© www.soinside.com 2019 - 2024. All rights reserved.