24 06 2015
Utilizando File Pickers em Windows Apps
Quem desenvolve para Windows Forms com certeza sabe que a maneira para possibilitarmos que o usuário selecione arquivos ou pastas é através da utilização das classes OpenFileDialog e FolderBrowserDialog. No WPF também temos o OpenFileDialog (só que localizado em outro namespace – Microsoft.Win32) e, para selecionarmos pastas, a recomendação é que utilizemos o FolderBrowserDialog do Windows Forms. Porém, como você deve ter percebido, tudo mudou no mundo dos Windows Apps (ou Windows Store Apps, ou Metro Style Apps – caramba, será que a Microsoft vai finalmente decidir como ela chamará esse tipo de aplicativo?). Nesse caso, temos que utilizar File Pickers, ou seja, as classes FileOpenPicker e FolderPicker. E é justamente esse o tema do artigo de hoje.
Vamos começar o nosso exemplo, como sempre, criando um projeto do tipo “Blank App“, que se encontra dentro da categoria “Store Apps” / “Windows Apps“. Após o Visual Studio ter criado o projeto, vamos até a MainPage adicionar um Button e um TextBlock dentro do Grid:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <StackPanel Margin="50"> <Button x:Name="SelecionarArquivoButton" Content="Selecionar Arquivo" Click="SelecionarArquivoButton_Click" /> <TextBlock x:Name="ResultadoTextBlock" /> </StackPanel> </Grid>
Feito isso, vamos até o code-behind para implementar o código do evento Click do botão (SelecionarArquivoButton_Click):
private async void SelecionarArquivoButton_Click(object sender, RoutedEventArgs e) { var fileOpenPicker = new Windows.Storage.Pickers.FileOpenPicker(); var file = await fileOpenPicker.PickSingleFileAsync(); if (file != null) ResultadoTextBlock.Text = file.Path; else ResultadoTextBlock.Text = string.Empty; }
Veja como é simples selecionar um arquivo em Windows Apps. Primeiro temos que criar uma instância da classe FileOpenPicker. Com ela, chamamos o método PickSingleFileAsync que, como o próprio nome diz, é assíncrono, portanto devemos utilizar a palavra-chave “await” em sua chamada (além disso, repare que tivemos que adicionar a palavra-chave “async” na assinatura do método). O retorno do método PickSingleFileAsync será “null” caso o usuário tenha cancelado a operação, ou um StorageFile caso o usuário tenha de fato selecionado um arquivo. Com o StorageFile em mãos, acessamos o seu caminho (através da propriedade Path) e exibimos o resultado no ResultadoTextBlock.
Simples, não? Pois tente executar a aplicação, clique no botão “Selecionar Arquivo” e veja o resultado:
The FileTypeFilters property must have at least one file type filter specified.
Bang! Exception na cabeça! Mas, por que? Por algum motivo inexplicável, a Microsoft decidiu que você obrigatoriamente tem que especificar um filtro de extensão de arquivo ao exibir FileOpenPickers. Esses filtros devem ser configurados através da propriedade FileTypeFilter.
FileTypeFilter
A propriedade FileTypeFilter serve, como o nome indica, para filtrarmos os tipos de arquivos que serão exibidos no FileOpenPicker. Como mencionei no parágrafo anterior, a Microsoft decidiu que temos que obrigatoriamente especificar um filtro quando exibimos FileOpenPickers. Mas, e se não quisermos filtrar os arquivos a serem exibidos? E se quisermos exibir todos os arquivos no diálogo do FileOpenPicker? Simples! Nesse caso, temos que adicionar um filtro com o tipo de arquivo “*” (asterisco):
var fileOpenPicker = new Windows.Storage.Pickers.FileOpenPicker(); fileOpenPicker.FileTypeFilter.Add("*"); var file = await fileOpenPicker.PickSingleFileAsync(); if (file != null) ResultadoTextBlock.Text = file.Path; else ResultadoTextBlock.Text = string.Empty;
Se pensarmos no OpenFileDialog do Windows Forms / WPF, tínhamos a propriedade Filter que servia para o mesmo propósito. Porém, no FileOpenPicker das Windows Apps, não podemos adicionar uma descrição à extensão como fazíamos antigamente, já que o FileOpenPicker nem exibe para o usuário quais são os filtros sendo aplicados. Isso, na minha opinião, acaba deixando o usuário confuso. Imagina você tendo que selecionar um arquivo sem saber quais as extensões de arquivos são suportadas? É por essas e outras que muita gente reclama das Windows Apps – praticamente tudo parece um retrocesso ao que temos disponível no desenvolvimento de aplicações desktop. Mas, enfim, isso é um assunto a parte – desculpe o meu desabafo!
Para adicionarmos um filtro de tipo de arquivo, basta utilizarmos a extensão desejada, incluindo o ponto inicial. Por exemplo, para exibirmos somente arquivos do tipo “docx“, basta adicionarmos o filtro “.docx“. Você pode adicionar vários filtros no mesmo FileOpenPicker, como “.doc” e “.docx“:
fileOpenPicker.FileTypeFilter.Add(".docx"); fileOpenPicker.FileTypeFilter.Add(".doc");
PickerViewMode
Por padrão, o FileOpenPicker exibe as pastas e arquivos em formato de lista, ou seja, com uma minúscula thumbnail e algumas informações sobre o arquivo, como você pode ver no exemplo abaixo:
Porém, em algumas situações, principalmente para selecionarmos arquivos de mídia (como fotos ou vídeos), essa não é a melhor opção. Nesse caso, seria mais interessante exibirmos as pastas e arquivos em um formato que consigamos ver melhor o conteúdo do arquivo. E acredito que foi pensando nessa situação que a propriedade ViewMode do FileOpenPicker foi criada. Com ela, podemos especificar que as pastas e arquivos sejam exibidos em formato thumbnail:
fileOpenPicker.ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail;
Veja a diferença no resultado:
SuggestedStartLocation
Não consegui entender exatamente qual é a pasta que o FileOpenPicker exibe por padrão, mas, através da propriedade SuggestedStartLocation conseguimos especificar a pasta que deverá ser exibida inicialmente pelo FileOpenPicker. Por exemplo, para que o FileOpenPicker seja iniciado na pasta “desktop“, utilize o trecho de código a seguir:
fileOpenPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.Desktop;
Porém, fique atento com essa propriedade, pois, não é possível simplesmente indicar qualquer caminho para a pasta inicial (como conseguíamos fazer anteriormente com o OpenFileDialog). Devido às limitações impostas pelo WinRT e seu modelo de sandbox, só conseguimos selecionar algumas pastas pré-definidas pelo enumerador PickerLocationId:
Selecionando múltiplos arquivos
Para selecionarmos múltiplos arquivos, ao invés de utilizarmos o método PickSingleFileAsync, temos que utilizar o método PickMultipleFilesAsync. Nesse caso, o retorno não será mais um único StorageFile, mas sim, uma lista de StorageFiles. Dessa forma, podemos iterar pelos arquivos e pegar cada um de seus caminhos:
private async void SelecionarArquivoButton_Click(object sender, RoutedEventArgs e) { var fileOpenPicker = new Windows.Storage.Pickers.FileOpenPicker(); fileOpenPicker.FileTypeFilter.Add("*"); var files = await fileOpenPicker.PickMultipleFilesAsync(); if (files != null) { System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder(); foreach (var file in files) stringBuilder.AppendLine(file.Path); ResultadoTextBlock.Text = stringBuilder.ToString(); } else ResultadoTextBlock.Text = string.Empty; }
FolderPicker
Até agora vimos como selecionar arquivos em Windows Apps. Mas, e se quisermos selecionar uma pasta ao invés de arquivos? No Windows Forms e WPF utilizaríamos o FolderBrowserDialog. E no WinRT? Qual classe temos que utilizar? Nesse caso, utilizamos a classe FolderPicker.
Essa classe possui a praticamente mesma estrutura da classe FileOpenPicker. A diferença é que, ao invés de chamarmos o método PickSingleFileAsync ou PickMultipleFilesAsync, temos que chamar o método PickSingleFolderAsync. Por mais incrível que pareça, apesar de não surtir nenhum resultado, somos obrigados a configurar um FileTypeFilter, senão receberemos a mesma exceção que recebemos anteriormente com o FileOpenPicker. Na minha opinião (e também na opinião de outras pessoas, veja só), essa foi um erro feio de API que o time do WinRT cometeu. O FileTypeFilter não faz nenhuma diferença ao selecionarmos uma pasta (podemos, por exemplo, configurar o FileTypeFilter como “.doc“, mas, isso não fará nenhuma diferença nas pastas que serão exibidas), então, por que temos que fornecer um FileTypeFilter? Enfim, para contornar esse problema, vamos configurar o FileTypeFilter como “*” (asterisco).
Vamos adicionar mais um botão no nosso StackPanel para fazermos a seleção da pasta:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <StackPanel Margin="50"> <Button x:Name="SelecionarArquivoButton" Content="Selecionar Arquivo" Click="SelecionarArquivoButton_Click" /> <Button x:Name="SelecionarPastaButton" Content="Selecionar Pasta" Click="SelecionarPastaButton_Click" /> <TextBlock x:Name="ResultadoTextBlock" /> </StackPanel> </Grid>
E então, vamos implementar o código para selecionarmos a pasta. Veja só que simples:
private async void SelecionarPastaButton_Click(object sender, RoutedEventArgs e) { var folderPicker = new Windows.Storage.Pickers.FolderPicker(); folderPicker.FileTypeFilter.Add("*"); var folder = await folderPicker.PickSingleFolderAsync(); if (folder != null) ResultadoTextBlock.Text = folder.Path; else ResultadoTextBlock.Text = string.Empty; }
Concluindo
Se você está acostumado a selecionar arquivos e pastas no WPF e Windows Forms, você sabe exatamente quais classes utilizar e como elas funcionam. Porém, no desenvolvimento de Windows Apps com o WinRT, tudo mudou. Nesse artigo você aprendeu como utilizar as classes FileOpenPicker e FolderPicker para selecionar arquivos e pastas no desenvolvimento de Windows Apps.
Por hoje é só. Espero que você tenha gostado. Não se esqueça de assinar a minha newsletter para ficar por dentro das novidades do meu site (para isso, utilize o formulário logo abaixo)!
Até a próxima!
André Lima
Implementando uma janela de login com Windows Forms ou WPF Meio ano se passou… E como estão as metas?