Pergunta

No VS .NET, quando você estiver selecionando uma pasta para um projeto, uma caixa de diálogo que se assemelha a um OpenFileDialog ou SaveFileDialog é exibida, mas é configurado para aceitar apenas as pastas.Desde que eu vi isso eu queria saber como é feito.Estou ciente de que o FolderBrowserDialog, mas eu nunca gostei muito de que a caixa de diálogo.Ele começa muito pequeno e não me deixar levar vantagem de ser capaz de escrever um caminho.

Eu estou quase certa que agora não há uma maneira de fazer isso .NET, mas eu estou tão curioso quanto você fazê-lo a partir de código não gerido como bem.Curta completamente reimplementing o diálogo a partir do zero, como você modificar o diálogo tem esse comportamento?

Eu também gostaria de reafirmar que estou ciente do FolderBrowserDialog mas às vezes eu não gostaria de usá-lo, além de ser genuinamente curioso como configurar uma caixa de diálogo dessa maneira.Me dizendo para usar apenas o FolderBrowserDialog ajuda-me a manter uma INTERFACE do usuário consistente experiência, mas não satisfaz a minha curiosidade e por isso não conta como uma resposta.

Não é uma Vista específica de coisa;Eu estive vendo esse diálogo desde VS .NET 2003, portanto, é factível no Win2k e WinXP.Isso é menos de um "eu quero saber a maneira correta de fazer isso" pergunta e mais de um "eu tenho curiosidade sobre isso desde que eu primeiro queria fazê-lo em VS 2003" pergunta.Eu entendo que a Vista de arquivo da caixa de diálogo tem uma opção para fazer isso, mas ele está trabalhando no XP, então eu sei que eles fizeram algo para fazê-lo funcionar.Vista-respostas não são as respostas, porque a Vista não existe a questão de contexto.

Atualização:Estou aceitando Scott Wisniewski a resposta de porque ele vem com uma amostra de trabalho, mas eu acho que Serge merece crédito por apontando para a caixa de diálogo de personalização (que é reconhecidamente desagradável de .NET mas não trabalho) e a Marca de Resgate para descobrir que a MS provavelmente rolou uma caixa de diálogo personalizada para esta tarefa.

Foi útil?

Solução

Eu tenho uma caixa de diálogo que escrevi, chamado um OpenFileOrFolder de diálogo que permite que você abrir uma pasta ou um arquivo.

Se você definir suas AcceptFiles valor para false e, em seguida, ele funciona apenas em aceitar o modo de pasta.

Você pode baixar o código fonte a partir do GitHub aqui

Outras dicas

Não é o Windows API Code Pack.Ele tem um monte de shell de coisas relacionadas, incluindo a CommonOpenFileDialog classe (no Microsoft.WindowsAPICodePack.Dialogs espaço de nomes).Esta é a solução perfeita - o costume de diálogo abrir com apenas pastas exibidas.

Aqui está um exemplo de como usá-lo:

CommonOpenFileDialog cofd = new CommonOpenFileDialog();
cofd.IsFolderPicker = true;
cofd.ShowDialog();

Infelizmente a Microsoft não mais enviado este pacote, mas várias pessoas não oficialmente enviados binários para o NuGet.Um exemplo pode ser encontrado aqui.Este pacote é apenas o shell de coisas específicas.Em caso de necessidade, o mesmo usuário tem vários outros pacotes que oferecem mais funcionalidade presente no pacote original.

Você pode usar FolderBrowserDialogEx - um re-utilizável derivados do built-in FolderBrowserDialog.Este permite que você digite um caminho, mesmo um caminho UNC.Você também pode procurar por computadores ou impressoras com ele.Funciona exatamente como o built-in FUP, mas ...a melhor.

(EDIÇÃO:Eu deveria ter destacou que este diálogo pode ser definido para selecionar arquivos ou pastas.)

O código Fonte completo (um curto C# módulo).Livre.MS-licença Pública.

Código para usá-lo:

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

O Ookii.Caixas de diálogo o pacote contém um wrapper gerido em torno do novo (do estilo do Vista) pasta de diálogo do navegador.Ele também diminui normalmente em sistemas operacionais mais antigos.

Melhor usar o FolderBrowserDialog para isso.

using (FolderBrowserDialog dlg = new FolderBrowserDialog())
{
    dlg.Description = "Select a folder";
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        MessageBox.Show("You selected: " + dlg.SelectedPath);
    }
}

Depois de horas de pesquisa, eu encontrei esta resposta por leetNightShade para uma solução de trabalho.

Há três coisas que eu acho que fazem esta solução muito melhor do que todos os outros.

  1. Ele é simples de usar. Ele só exige que você incluir dois arquivos (que podem ser combinados para um de qualquer maneira) em seu projeto.
  2. Ela cai de volta para o padrão FolderBrowserDialog quando usado no XP ou sistemas mais antigos.
  3. O autor concede permissão para usar o código para qualquer finalidade que bem entenderem.

    Não há nenhuma licença como tal, você é livre para tomar e fazer com que o código que você vai.

Baixe o código aqui.

Exact Audio Copy funciona dessa maneira no Windows XP.O padrão de diálogo abrir ficheiro é mostrada, mas o campo de nome de arquivo contém o texto "nome do arquivo será ignorado".

Apenas supondo aqui, mas eu suspeito que a cadeia é injetado na caixa de combinação controle de edição cada vez que uma significativa alteração é feita para o diálogo.Enquanto o campo não está vazio, e o diálogo flags estão definidas para não verificar a existência do arquivo, a caixa de diálogo pode ser fechado normalmente.

Editar: isso é muito mais fácil do que eu pensava.Aqui está o código em C++/MFC, você pode traduzi-lo para o ambiente de sua escolha.

CFileDialog dlg(true, NULL, "Filename will be ignored", OFN_HIDEREADONLY | OFN_NOVALIDATE | OFN_PATHMUSTEXIST | OFN_READONLY, NULL, this);
dlg.DoModal();

Edit 2: Esta deve ser a tradução para C#, mas eu não sou fluente em C# para não atirar em mim, se ele não 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
}

Edit 3: Finalmente olhou para o diálogo real em questão, no Visual Studio 2005 (não tive acesso a ela anteriores). Não é o padrão de diálogo abrir arquivo! Se você inspecionar o windows em Spy++ e compará-los a um padrão de arquivo aberto, você vai ver que a estrutura de classe e os nomes não correspondem.Quando você olhar de perto, você também pode observar algumas diferenças entre o conteúdo das caixas de diálogo.Minha conclusão é de que a Microsoft substituído completamente o padrão de caixa de diálogo no Visual Studio para lhe dar esta capacidade.A minha solução ou algo similar será tão perto como você pode começar, a menos que você está disposto a código de seu próprio a partir do zero.

OK, deixem-me tentar conectar-se o primeiro ponto ;-) Brincando um pouco com Spy++ ou Winspector mostra que a Pasta de caixa de texto no Projeto do VS Local é uma personalização da caixa de diálogo padrão.Não é a mesma de campo como o nome do arquivo de texto em uma caixa de diálogo arquivo padrão como o bloco de notas.

A partir daí, eu acho, VS esconde o nome de arquivo e o tipo de arquivo de caixas de texto/comboboxes e utiliza um modelo de diálogo personalizada para adicionar o seu próprio papel na parte inferior da caixa de diálogo.

EDITAR:Aqui está um exemplo de como a personalização e o como fazer (em Win32.não .NET):

m_ofn é OPENFILENAME estrutura que sustenta a caixa de diálogo de arquivo.Adicione estas 2 linhas:

  m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEDIALOG_IMPORTXLIFF);
  m_ofn.Flags |= OFN_ENABLETEMPLATE;

onde IDD_FILEDIALOG_IMPORTXLIFF é um modelo de diálogo personalizada que será adicionado na parte inferior da caixa de diálogo.Veja a parte em vermelho abaixo.alt text
(fonte: apptranslator.com)

Neste caso, a peça é apenas um rótulo + um hiperlink, mas poderia ser qualquer diálogo.Ele pode conter um botão OK que deixar-nos validar pasta somente a seleção.

Mas, como seria de se livrar de alguns dos controles na parte padrão da caixa de diálogo, eu não sei.

Mais detalhes em este artigo do MSDN.

Você pode subclasse caixa de diálogo de ficheiro e ter acesso a todos os seus controles.Cada um tem um identificador que pode ser usado para obter o identificador de janela.Em seguida, você pode mostrar e ocultar-las, obter mensagens sobre alterações de seleção etc.etc.Tudo depende de quanto de esforço você quer tomar.

Nós fizemos a nossa utilizando WTL classe de suporte personalizado e o arquivo de caixa de diálogo para incluir um costume barra de locais de plug-in e COM pontos de vista.

MSDN fornece informações sobre como fazer isso usando Win32, este CodeProject artigo inclui um exemplo, e este CodeProject artigo fornece uma .NET exemplo.

Você pode usar o código como este

  • O filtro é ocultar arquivos
  • O nome do arquivo é ocultar primeiro texto

A avançada esconder de caixa de texto nome do arquivo que você precisa para olhar OpenFileDialogEx

Código:

{
    openFileDialog2.FileName = "\r";
    openFileDialog1.Filter = "folders|*.neverseenthisfile";
    openFileDialog1.CheckFileExists = false;
    openFileDialog1.CheckPathExists = false;
}

Eu suponho que você está no windows Vista, usando o VS2008?Nesse caso eu acho que o FOS_PICKFOLDERS opção está sendo usado ao chamar a Vista de diálogo de ficheiro IFileDialog.Tenho medo de que no .LÍQUIDO código isso envolveria uma abundância de rugosidade P/Invoke código de interoperabilidade para começar a trabalhar.

Primeira Solução

Eu desenvolvi este como um limpos versão .Ganho LÍQUIDO 7-estilo de diálogo selecionar pasta pelo projeto de lei de Seddon lyquidity.com (Eu não tenho nenhuma afiliação).(Eu soube que seu código de outra resposta sobre esta página).Eu escrevi o meu próprio, porque a sua solução requer um adicional de Reflexão classe que não é necessário para esta focada finalidade, utiliza exceção de controle de fluxo, não armazena em cache os resultados de sua reflexão chamadas.Observe que o aninhada estática VistaDialog classe, de modo a que a sua reflexão estática variáveis não tentar obter preenchido se o Show método nunca é chamado.Ela cai de volta para a pré-Vista de diálogo se não alto o suficiente versão do Windows.Deve funcionar no Windows 7, 8, 9, 10 e superior (teoricamente).

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

Ele é usado como um Formulário do Windows:

var dialog = new FolderSelectDialog {
    InitialDirectory = musicFolderTextBox.Text,
    Title = "Select a folder to import music from"
};
if (dialog.Show(Handle)) {
    musicFolderTextBox.Text = dialog.FileName;
}

É claro que você pode brincar com as suas opções e as propriedades que ele expõe.Por exemplo, ele permite que várias seleções na Vista de diálogo estilo.

Segunda Solução

Simon Mourier deu uma resposta que mostra como fazer exatamente o mesmo trabalho com interoperabilidade contra a API do Windows diretamente, embora sua versão devem ser completadas para utilizar o antigo estilo de diálogo se em uma versão mais antiga do Windows.Infelizmente, eu não tinha encontrado o seu post, mas quando eu trabalhei até a minha solução.Nome do seu veneno!

Tente esta Codeproject (crédito para Nitron):

Eu acho que é a mesma caixa de diálogo que você está falando - talvez ajudasse se você adicionar uma imagem?

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

No Vista, você pode usar IFileDialog com FOS_PICKFOLDERS conjunto de opções.Que vai causar a exibição de OpenFileDialog-como janela onde você pode selecionar pastas:

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 os Windows mais antigos, você pode sempre recorrer ao truque com a seleção de qualquer ficheiro na pasta.

Exemplo de trabalho que funciona .NET Framework 2.0 e, mais tarde, pode ser encontrado aqui.

Você pode usar o código como este

O filtro é de seqüência de caracteres vazia.O nome do arquivo é AnyName mas não em branco

        openFileDialog.FileName = "AnyFile";
        openFileDialog.Filter = string.Empty;
        openFileDialog.CheckFileExists = false;
        openFileDialog.CheckPathExists = false;

O Ookii caixas de diálogo para o WPF a biblioteca tem uma classe que fornece uma implementação de um navegador de pastas de diálogo para WPF.

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

enter image description here

Há também uma versão que funciona com Windows Forms.

Eu sei que a pergunta foi sobre a configuração de OpenFileDialog mas, vendo que o Google me trouxe aqui, posso muito bem apontam que, se você está olhando APENAS para as pastas que você deve estar usando um FolderBrowserDialog Em vez disso, como respondido por outro, PARA a pergunta abaixo

Como especificar o caminho usando a caixa de diálogo abrir arquivo em vb.net?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top