André Alves de Lima

Talking about Software Development and more…

WPF – Criando Jumplists na Taskbar do Windows 7

[Atenção!!! Este artigo tem sua versão em vídeo! Se quiser pular a parte escrita e só assistir o vídeo, dê uma olhada no final do post!]

Olá pessoal, tudo certo?

No artigo / vídeo de hoje vou dar continuidade à série que mostra como interagir com a Taskbar do Windows 7 através de nossas aplicações WPF. O tema deste artigo especificamente é a criação de JumpLists na Taskbar.

Com certeza você já deve ter percebido que algumas aplicações apresentam alguns itens ao clicar no ícone delas na Taskbar do Windows 7. Por exemplo, o Microsoft Outlook mostra uma lista de tarefas que podem ser executadas dentro dele, como criar um novo e-mail, criar uma nova tarefa, etc. Já no caso do Windows Explorer, ele mostra os arquivos / caminhos mais frequentemente acessados.


JumpList do Microsoft Outlook


JumpList do Windows Explorer

Que tal se conseguíssemos criar itens personalizados para a nossa aplicação, com funcionalidades que fazem sentido para a nossa realidade? Pois isso obviamente é possível (e fácil)!

Iniciemos criando um projeto do tipo WPF Application no Visual Studio 2010, utilizando o .NET Framework 4. A nossa aplicação será um visualizador de arquivos texto bem simples, já que o objetivo principal do artigo é demonstrar a funcionalidade de criação de jumplists. Portanto, na MainWindow que é criada automaticamente no nosso novo projeto, vamos adicionar um Button para exibir uma janela e selecionarmos um arquivo texto e um FlowDocumentReader, para exibir o conteúdo do arquivo selecionado. O XAML e a interface devem ficar parecidos com o seguinte:

O próximo passo é implementarmos o código do click do nosso Button, que deverá exibir um diálogo para selecionarmos o arquivo texto a ser aberto e na sequência deverá exibir esse arquivo no nosso FlowDocumentReader. Para isso, vamos implementar no código C# da nossa Window o seguinte método:

public void ExibirArquivo(string caminho)
{
    Paragraph paragraph = new Paragraph();
    paragraph.Inlines.Add(System.IO.File.ReadAllText(caminho));
    FlowDocument document = new FlowDocument(paragraph);
    fdrConteudoArquivo.Document = document;
}

Basicamente o método acima recebe o caminho de um arquivo e exibe o conteúdo desse arquivo no nosso FlowDocumentReader. Feito isso, podemos agora implementar o código do evento Click do nosso botão como abaixo:

private void btAbrir_Click(object sender, RoutedEventArgs e)
{
    Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog();

    dialog.Filter = "Text documents (.txt)|*.txt";
    bool? result = dialog.ShowDialog();
    if ((result != null) &&
        ((bool)result))
        ExibirArquivo(dialog.FileName);
}

Com isso, se você executar a aplicação verá que já podemos selecionar o arquivo desejado clicando no botão e ele será exibido no FlowDocumentReader. Agora vem a parte de fazermos a interface com a jumplist. A ideia é mostrar na jumplist a lista de arquivos que foram abertos pelo usuário. Para fazer isso, vamos criar no nosso código C# o seguinte método:

private System.Windows.Shell.JumpList jumpList = new System.Windows.Shell.JumpList();

private void AdicionaNaJumpList(string caminho)
{
    // Primeiro verificando se o item já está presente na JumpList (para evitar duplicidade).
    bool itemJaExiste = false;

    foreach (System.Windows.Shell.JumpItem jumpItem in jumpList.JumpItems)
    {
        if ((jumpItem is System.Windows.Shell.JumpTask) &&
            (((System.Windows.Shell.JumpTask)jumpItem).Arguments.Equals(caminho)))
        {
            itemJaExiste = true;
            break;
        }
    }

    // Se o item ainda não existe na JumpList, vamos adicioná-lo.
    if (!itemJaExiste)
    {
        // Configurando a JumpList da nossa aplicação para que ela seja o nosso atributo jumpList.
        System.Windows.Shell.JumpList.SetJumpList(Application.Current, jumpList);

        // Criando uma nova JumpTask.
        System.Windows.Shell.JumpTask jumpTask = new System.Windows.Shell.JumpTask();
        jumpTask.Title = System.IO.Path.GetFileNameWithoutExtension(caminho);
        jumpTask.ApplicationPath = "notepad.exe";
        jumpTask.Arguments = caminho;
        // Incluindo a JumpTask na nossa JumpList.
        jumpList.JumpItems.Add(jumpTask);

        // Confirmando as alterações da nossa JumpList.
        jumpList.Apply();
    }
}

Finalmente, precisamos incluir a chamada desse código no nosso método que abre o arquivo:

public void ExibirArquivo(string caminho)
{
    Paragraph paragraph = new Paragraph();
    paragraph.Inlines.Add(System.IO.File.ReadAllText(caminho));
    FlowDocument document = new FlowDocument(paragraph);
    fdrConteudoArquivo.Document = document;
    // Adicionando o item na JumpList.
    AdicionaNaJumpList(caminho);
}

Execute a aplicação e note que toda vez que um arquivo é aberto o nome do arquivo é adicionado na JumpList:

Ao clicarmos em algum dos itens na jumplist o arquivo será aberto no notepad. Isso acontece pois informamos no ApplicationPath da JumpTask que a aplicação chamada será o notepad.exe e que o argumento passado para ele será o caminho para o arquivo.

Mas, e se quisermos que ao clicar no item a nossa aplicação abra o arquivo? Para isso precisamos primeiramente fazer com que nossa aplicação somente possa ser executada uma vez e que ela trate os argumentos recebidos. Isso não é tão trivial de ser feito em WPF, mas, para nossa sorte, alguém já passou por isso e construiu uma solução simples e que funciona muito bem. Para maiores informações, dê uma olhada neste link.

Seguindo os passos do link acima, vamos ajustar nossa aplicação para que seja executada somente uma vez e que trate o argumento recebido para que o arquivo seja exibido no FlowDocumentReader, caso uma instância da aplicação já esteja sendo executada.

A primeira coisa a fazer é adicionar o arquivo SingleInstance.cs no nosso projeto. Após isso, devemos adicionar a referência a System.Runtime.Remoting no nosso projeto.

Em seguida, devemos ajustar o nosso arquivo App.xaml.cs para que a classe App implemente a interface ISingleInstanceApp e faça os tratementos necessários para a segunda execução da nossa aplicação. No nosso caso, o arquivo App.xaml.cs deve ser alterado para o seguinte:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;

namespace WpfApplication6
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application, Microsoft.Shell.ISingleInstanceApp
    {
        private const string Unique = "IdentificadorUnicoDaSuaAplicacao";
        [STAThread]
        // O método Main será executado quando ainda não houver outra instância do nosso aplicativo sendo executado.
        public static void Main(string[] args)
        {
            if (Microsoft.Shell.SingleInstance<App>.InitializeAsFirstInstance(Unique))
            {
                var application = new App();
                application.InitializeComponent();
                application.Run();
                // Tratando o caso em que o usuário clica em um item da jumplist e nossa aplicação não está aberta.
                if (args.Length > 1)
                    ((MainWindow)application.MainWindow).ExibirArquivo(ConstroiCaminhoCompleto(args));
                Microsoft.Shell.SingleInstance<App>.Cleanup();
            }
        }

        private static string ConstroiCaminhoCompleto(IEnumerable<string> args)
        {
            string resultado = string.Empty;

            System.Text.StringBuilder caminhoCompleto = new System.Text.StringBuilder();

            for (int contador = 1; contador < args.Count(); contador++)
                caminhoCompleto.Append(string.Format(" {0}", args.ElementAt(contador)));

            return caminhoCompleto.ToString();
        }

        #region ISingleInstanceApp Members
        // Esse método será chamado toda vez que nossa aplicação já estiver sendo
        // executada e o usuário clicar em um dos itens da jumplist.
        public bool SignalExternalCommandLineArgs(IList<string> args)
        {
            // Nesse caso, basta notificar nossa MainWindow para que ela exiba o
            // arquivo escolhido no nosso FlowDocumentReader.
            ((MainWindow)this.MainWindow).ExibirArquivo(ConstroiCaminhoCompleto(args));
            return true;
        }
        #endregion
    }
}

Por fim, precisamos indicar nos itens que serão criados na nossa JumpList que não será o notepad.exe que deverá abrir o arquivo, mas sim a nossa aplicação. Para isso basta alterar a linha onde setamos o ApplicationPath da nossa JumpTask para o seguinte:

jumpTask.ApplicationPath = System.Reflection.Assembly.GetEntryAssembly().Location;

Pronto! Com isso já temos nossa JumpList totalmente funcional, abrindo os arquivos na própria aplicação. Existem algumas propriedades interessantes que podemos configurar nas nossas JumpTasks. Veja a lista dos principais abaixo:

Description: para configurar a ToolTip do item da JumpList;
IconResourcePath e IconResourceIndes: para informar qual será o ícone utilizado no item da JumpList;
CustomCategory: por padrão os itens são adicionados na categoria “Tasks” da JumpList. Para incluí-los em uma categoria customizada, é só informar uma string nessa propriedade.

Também podemos utilizar as seguintes propriedades / método do nosso objeto JumpList:

ShowRecentCategory: para habilitar a categoria de itens recentes (o padrão é desabilitado);
AddToRecentCategory(JumpItem): para adicionar um item na lista de itens recentes;
ShowFrequentCategory: para habilitar a categoria de itens frequentes (o padrão é desabilitado). O mais interessante aqui é que basta habilitar a funcionalidade e o Windows toma conta de mostrar os itens mais frequentes automaticamente pra gente!

Além de JumpTasks, podemos criar também JumpPaths, porém, não mostrarei como criá-los neste artigo já que a criação é exatamente semelhante à criação de JumpTasks, exceto que a única propriedade disponível é a Path, que indica o caminho do arquivo que deve ser aberto pela aplicação default daquela extensão. Seria o mesmo que clicarmos para abrir o arquivo no Windows Explorer.

Devemos lembrar também que os itens podem ser criados diretamente no XAML da nossa Application, mas, dessa forma os itens são estáticos, por isso, só demonstrei a criação de itens através do C#, o que possibilita a criação de itens em runtime.

É isso aí! Espero que vocês tenham gostado desse artigo e que comecem a adicionar funcionalidades na JumpList das suas aplicações!

Abaixo vocês podem assistir o vídeo que mostra um passo-a-passo do conteúdo apresentado no artigo.

[Observação: para assistir o vídeo em uma qualidade melhor, clique no botão HD do Media Player abaixo]

Até a próxima!

André Alves de Lima.

7 thoughts on “WPF – Criando Jumplists na Taskbar do Windows 7

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *