Estender as janelas Propriedades, Lista de Tarefas, Saída e Opções

Você pode acessar qualquer janela de ferramenta no Visual Studio. Este passo a passo mostra como integrar informações sobre a janela de ferramentas em uma nova página Opções e uma nova configuração na página Propriedades, e também como gravar nas janelas Lista de Tarefas e Saída.

Criar uma extensão com uma janela de ferramenta

  1. Crie um projeto chamado TodoList usando o modelo VSIX e adicione um modelo de item de janela de ferramenta personalizado chamado TodoWindow.

    Observação

    Para obter mais informações sobre como criar uma extensão com uma janela de ferramenta, consulte Criar uma extensão com uma janela de ferramenta.

Configurar a janela de ferramentas

Adicione um TextBox no qual digitar um novo item ToDo, um Button para adicionar o novo item à lista e um ListBox para exibir os itens na lista.

  1. Em TodoWindow.xaml, exclua os controles Button, TextBox e StackPanel do UserControl.

    Observação

    Isso não exclui o manipulador de eventos button1_Click, que você reutilizará em uma etapa posterior.

  2. Na seção Todos os Controles WPF da Caixa de Ferramentas, arraste um controle Canvas para a grade.

  3. Arraste um TextBox, um Button e um ListBox para a tela. Organize os elementos de modo que o TextBox e o Button estejam no mesmo nível, e o ListBox preencha o restante da janela abaixo deles, como na imagem abaixo.

    Finished Tool Window

  4. No painel XAML, localize o Button e defina sua propriedade Content como Add. Reconecte o manipulador de eventos button ao controle Button adicionando um Click="button1_Click" atributo. O bloco Canvas deve ter esta aparência:

    <Canvas HorizontalAlignment="Left" Width="306">
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="208"/>
            <Button x:Name="button" Content="Add" HorizontalAlignment="Left" Margin="236,13,0,0" VerticalAlignment="Top" Width="48" Click="button1_Click"/>
            <ListBox x:Name="listBox" HorizontalAlignment="Left" Height="222" Margin="10,56,0,0" VerticalAlignment="Top" Width="274"/>
    </Canvas>
    

Personalizar o construtor

  1. No arquivo TodoWindowControl.xaml.cs adicione a seguinte diretiva using:

    using System;
    
  2. Adicione uma referência pública ao TodoWindow e faça com que o construtor TodoWindowControl use um parâmetro TodoWindow. Seu código deve ficar assim:

    public TodoWindow parent;
    
    public TodoWindowControl(TodoWindow window)
    {
        InitializeComponent();
        parent = window;
    }
    
  3. Em TodoWindow.cs, altere o construtor TodoWindowControl para incluir o parâmetro TodoWindow. Seu código deve ficar assim:

    public TodoWindow() : base(null)
    {
        this.Caption = "TodoWindow";
        this.BitmapResourceID = 301;
        this.BitmapIndex = 1;
    
         this.Content = new TodoWindowControl(this);
    }
    

Criar uma página Opções

Você pode fornecer uma página na caixa de diálogo Opções para que os usuários possam alterar as configurações da janela da ferramenta. A criação de uma página Opções requer uma classe que descreva as opções e uma entrada no arquivo TodoListPackage.cs ou TodoListPackage.vb de dados.

  1. Adicione uma classe chamada ToolsOptions.cs. Faça a ToolsOptions classe herdar de DialogPage.

    class ToolsOptions : DialogPage
    {
    }
    
  2. Adicione a seguinte diretiva de uso:

    using Microsoft.VisualStudio.Shell;
    
  3. A página Opções neste passo a passo fornece apenas uma opção chamada DaysAhead. Adicione um campo privado chamado daysAhead e uma propriedade chamada DaysAhead à ToolsOptions classe:

    private double daysAhead;
    
    public double DaysAhead
    {
        get { return daysAhead; }
        set { daysAhead = value; }
    }
    

    Agora você deve tornar o projeto ciente desta página Opções.

Disponibilizar a página Opções para os usuários

  1. Em TodoWindowPackage.cs, adicione um ProvideOptionPageAttribute à TodoWindowPackage classe:

    [ProvideOptionPage(typeof(ToolsOptions), "ToDo", "General", 101, 106, true)]
    
  2. O primeiro parâmetro para o construtor ProvideOptionPage é o tipo da classe ToolsOptions, que você criou anteriormente. O segundo parâmetro, "ToDo", é o nome da categoria na caixa de diálogo Opções . O terceiro parâmetro, "Geral", é o nome da subcategoria da caixa de diálogo Opções onde a página Opções estará disponível. Os próximos dois parâmetros são IDs de recurso para cadeias de caracteres; o primeiro é o nome da categoria, e o segundo é o nome da subcategoria. O parâmetro final determina se essa página pode ser acessada usando automação.

    Quando um usuário abre sua página Opções, ela deve ser semelhante à imagem a seguir.

    Options Page

    Observe a categoria ToDo e a subcategoria Geral.

Disponibilizar dados para a janela Propriedades

Você pode disponibilizar informações de lista de tarefas pendentes criando uma classe chamada TodoItem que armazena informações sobre os itens individuais na lista de tarefas pendentes.

  1. Adicione uma classe chamada TodoItem.cs.

    Quando a janela de ferramenta estiver disponível para os usuários, os itens na ListBox serão representados por TodoItems. Quando o usuário seleciona um desses itens na ListBox, a janela Propriedades exibirá informações sobre o item.

    Para disponibilizar dados na janela Propriedades , transforme os dados em propriedades públicas que tenham dois atributos Description especiais e Category. Description é o texto que aparece na parte inferior da janela Propriedades . Category determina onde a propriedade deve aparecer quando a janela Propriedades é exibida no modo de exibição Categorizado . Na imagem a seguir, a janela Propriedades está no modo de exibição Categorizado, a propriedade Name na categoria Campos ToDo é selecionada e a descrição da propriedade Name é exibida na parte inferior da janela.

    Properties Window

  2. Adicione o seguinte usando diretivas o arquivo TodoItem.cs .

    using System.ComponentModel;
    using System.Windows.Forms;
    using Microsoft.VisualStudio.Shell.Interop;
    
  3. Adicione o public modificador de acesso à declaração de classe.

    public class TodoItem
    {
    }
    

    Adicione as duas propriedades Name e DueDate. Faremos o UpdateList() e CheckForErrors() mais tarde.

    public class TodoItem
    {
        private TodoWindowControl parent;
        private string name;
        [Description("Name of the ToDo item")]
        [Category("ToDo Fields")]
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                parent.UpdateList(this);
            }
        }
    
        private DateTime dueDate;
        [Description("Due date of the ToDo item")]
        [Category("ToDo Fields")]
        public DateTime DueDate
        {
            get { return dueDate; }
            set
            {
                dueDate = value;
                parent.UpdateList(this);
                parent.CheckForErrors();
            }
        }
    }
    
  4. Adicione uma referência privada ao controle de usuário. Adicione um construtor que usa o controle de usuário e o nome para este item ToDo. Para localizar o valor do daysAhead, ele obtém a propriedade de página Opções.

    private TodoWindowControl parent;
    
    public TodoItem(TodoWindowControl control, string itemName)
    {
        parent = control;
        name = itemName;
        dueDate = DateTime.Now;
    
        double daysAhead = 0;
        IVsPackage package = parent.parent.Package as IVsPackage;
        if (package != null)
        {
            object obj;
            package.GetAutomationObject("ToDo.General", out obj);
    
            ToolsOptions options = obj as ToolsOptions;
            if (options != null)
            {
                daysAhead = options.DaysAhead;
            }
        }
    
        dueDate = dueDate.AddDays(daysAhead);
    }
    
  5. Como as TodoItem instâncias da classe serão armazenadas no ListBox e o ListBox chamará a função, você deve sobrecarregar a ToString ToString função. Adicione o seguinte código a TodoItem.cs, após o construtor e antes do final da classe.

    public override string ToString()
    {
        return name + " Due: " + dueDate.ToShortDateString();
    }
    
  6. Em TodoWindowControl.xaml.cs, adicione métodos stub à TodoWindowControl classe para os CheckForError métodos e UpdateList . Coloque-os após o ProcessDialogChar e antes do final do arquivo.

    public void CheckForErrors()
    {
    }
    public void UpdateList(TodoItem item)
    {
    }
    

    O CheckForError método chamará um método que tem o mesmo nome no objeto pai e esse método verificará se ocorreram erros e os manipulará corretamente. O UpdateList método atualizará o ListBox no controle pai, o método é chamado quando as propriedades e DueDate nessa Name classe são alteradas. Eles serão implementados posteriormente.

Integrar na janela Propriedades

Agora escreva o código que gerencia a ListBox, que será vinculada à janela Propriedades .

Você deve alterar o manipulador de clique de botão para ler o TextBox, criar um TodoItem e adicioná-lo à ListBox.

  1. Substitua a função existente button1_Click por código que cria um novo TodoItem e o adiciona à ListBox. Chama, TrackSelection()que será definido posteriormente.

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        if (textBox.Text.Length > 0)
        {
            var item = new TodoItem(this, textBox.Text);
            listBox.Items.Add(item);
            TrackSelection();
            CheckForErrors();
        }
    }
    
  2. No modo Design, selecione o controle ListBox. Na janela Propriedades, clique no botão Manipuladores de eventos e localize o evento SelectionChanged. Preencha a caixa de texto com listBox_SelectionChanged. Isso adiciona um stub para um manipulador SelectionChanged e o atribui ao evento.

  3. Implementar o método de TrackSelection() . Uma vez que você precisará obter os SVsUIShellSTrackSelection serviços, você precisa torná-lo GetService acessível pelo TodoWindowControl. Adicione o seguinte método à classe TodoWindow:

    internal object GetVsService(Type service)
    {
        return GetService(service);
    }
    
  4. Adicione as seguintes diretivas usando a TodoWindowControl.xaml.cs:

    using System.Runtime.InteropServices;
    using Microsoft.VisualStudio.Shell.Interop;
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.Shell;
    
  5. Preencha o manipulador SelectionChanged da seguinte maneira:

    private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        TrackSelection();
    }
    
  6. Agora, preencha a função TrackSelection, que fornecerá integração com a janela Propriedades . Essa função é chamada quando o usuário adiciona um item à ListBox ou clica em um item na ListBox. Ele adiciona o conteúdo do ListBox a um SelectionContainer e passa o SelectionContainer para o manipulador de eventos da OnSelectChange janela Propriedades. O serviço TrackSelection rastreia objetos selecionados na interface do usuário (UI) e exibe suas propriedades

    private SelectionContainer mySelContainer;
    private System.Collections.ArrayList mySelItems;
    private IVsWindowFrame frame = null;
    
    private void TrackSelection()
    {
        if (frame == null)
        {
            var shell = parent.GetVsService(typeof(SVsUIShell)) as IVsUIShell;
            if (shell != null)
            {
                var guidPropertyBrowser = new
                Guid(ToolWindowGuids.PropertyBrowser);
                shell.FindToolWindow((uint)__VSFINDTOOLWIN.FTW_fForceCreate,
                ref guidPropertyBrowser, out frame);
            }
        }
        if (frame != null)
            {
                frame.Show();
            }
        if (mySelContainer == null)
        {
            mySelContainer = new SelectionContainer();
        }
    
        mySelItems = new System.Collections.ArrayList();
    
        var selected = listBox.SelectedItem as TodoItem;
        if (selected != null)
        {
            mySelItems.Add(selected);
        }
    
        mySelContainer.SelectedObjects = mySelItems;
    
        ITrackSelection track = parent.GetVsService(typeof(STrackSelection))
                                as ITrackSelection;
        if (track != null)
        {
            track.OnSelectChange(mySelContainer);
        }
    }
    

    Agora que você tem uma classe que a janela Propriedades pode usar, você pode integrar a janela Propriedades com a janela de ferramenta. Quando o usuário clica em um item na ListBox na janela da ferramenta, a janela Propriedades deve ser atualizada de acordo. Da mesma forma, quando o usuário altera um item ToDo na janela Propriedades , o item associado deve ser atualizado.

  7. Agora, adicione o restante do código de função UpdateList em TodoWindowControl.xaml.cs. Ele deve soltar e adicionar novamente o TodoItem modificado da ListBox.

    public void UpdateList(TodoItem item)
    {
        var index = listBox.SelectedIndex;
        listBox.Items.RemoveAt(index);
        listBox.Items.Insert(index, item);
        listBox.SelectedItem = index;
    }
    
  8. Teste seu código. Compile o projeto e comece a depuração. A instância experimental deve aparecer.

  9. Abra a página Opções de Ferramentas>. Você deve ver a categoria ToDo no painel esquerdo. As categorias estão listadas em ordem alfabética, então olhe abaixo do Ts.

  10. Na página Opções de todo , você deve ver a DaysAhead propriedade definida como 0. Mude-o para 2.

  11. No menu Exibir / Outro Windows, abra TodoWindow. Digite EndDate na caixa de texto e clique em Adicionar.

  12. Na caixa de listagem, você deve ver uma data dois dias depois de hoje.

Adicionar texto à janela Saída e itens à Lista de Tarefas

Para a Lista de Tarefas, crie um novo objeto do tipo Task e adicione esse objeto Task à Lista de Tarefas chamando seu Add método. Para gravar na janela Saída , chame seu GetPane método para obter um objeto de painel e, em seguida, chame o OutputString método do objeto de painel.

  1. Em TodoWindowControl.xaml.cs, no button1_Click método, adicione código para obter o painel Geral da janela Saída (que é o padrão) e grave nele. O método deverá ter esta aparência:

    private void button1_Click(object sender, EventArgs e)
    {
        if (textBox.Text.Length > 0)
        {
            var item = new TodoItem(this, textBox.Text);
            listBox.Items.Add(item);
    
            var outputWindow = parent.GetVsService(
                typeof(SVsOutputWindow)) as IVsOutputWindow;
            IVsOutputWindowPane pane;
            Guid guidGeneralPane = VSConstants.GUID_OutWindowGeneralPane;
            outputWindow.GetPane(ref guidGeneralPane, out pane);
            if (pane != null)
            {
                 pane.OutputString(string.Format(
                    "To Do item created: {0}\r\n",
                 item.ToString()));
        }
            TrackSelection();
            CheckForErrors();
        }
    }
    
  2. Para adicionar itens à Lista de Tarefas, você precisa de um para adicionar uma classe aninhada à classe TodoWindowControl. A classe aninhada precisa derivar de TaskProvider. Adicione o seguinte código ao final da TodoWindowControl classe.

    [Guid("72de1eAD-a00c-4f57-bff7-57edb162d0be")]
    public class TodoWindowTaskProvider : TaskProvider
    {
        public TodoWindowTaskProvider(IServiceProvider sp)
            : base(sp)
        {
        }
    }
    
  3. Em seguida, adicione uma referência privada e TodoTaskProvider um CreateProvider() método à TodoWindowControl classe. Seu código deve ficar assim:

    private TodoWindowTaskProvider taskProvider;
    private void CreateProvider()
    {
        if (taskProvider == null)
        {
            taskProvider = new TodoWindowTaskProvider(parent);
            taskProvider.ProviderName = "To Do";
        }
    }
    
  4. Adicione ClearError(), que limpa a Lista de Tarefas e ReportError(), que adiciona uma entrada à Lista de Tarefas, à TodoWindowControl classe.

    private void ClearError()
    {
        CreateProvider();
        taskProvider.Tasks.Clear();
    }
    private void ReportError(string p)
    {
        CreateProvider();
        var errorTask = new Task();
        errorTask.CanDelete = false;
        errorTask.Category = TaskCategory.Comments;
        errorTask.Text = p;
    
        taskProvider.Tasks.Add(errorTask);
    
        taskProvider.Show();
    
        var taskList = parent.GetVsService(typeof(SVsTaskList))
            as IVsTaskList2;
        if (taskList == null)
        {
            return;
        }
    
        var guidProvider = typeof(TodoWindowTaskProvider).GUID;
         taskList.SetActiveProvider(ref guidProvider);
    }
    
  5. Agora implemente o CheckForErrors método, da seguinte maneira.

    public void CheckForErrors()
    {
        foreach (TodoItem item in listBox.Items)
        {
            if (item.DueDate < DateTime.Now)
            {
                ReportError("To Do Item is out of date: "
                    + item.ToString());
            }
        }
    }
    

Experimente

  1. Compile o projeto e comece a depuração. A instância experimental é exibida.

  2. Abra o TodoWindow (Exibir>outro>Windows TodoWindow).

  3. Digite algo na caixa de texto e clique em Adicionar.

    Uma data de vencimento 2 dias após hoje é adicionada à caixa de listagem. Nenhum erro é gerado e a Lista de Tarefas (Exibir>Lista de Tarefas) não deve ter entradas.

  4. Agora altere a configuração na página Opções>de Ferramentas>ToDo de 2 para 0.

  5. Digite outra coisa no TodoWindow e, em seguida, clique em Adicionar novamente. Isso dispara um erro e também uma entrada na Lista de Tarefas.

    À medida que você adiciona itens, a data inicial é definida como agora mais 2 dias.

  6. No menu Exibir, clique em Saída para abrir a janela Saída.

    Observe que sempre que você adiciona um item, uma mensagem é exibida no painel Lista de Tarefas.

  7. Clique em um dos itens na ListBox.

    A janela Propriedades exibe as duas propriedades do item.

  8. Altere uma das propriedades e pressione Enter.

    O item é atualizado na ListBox.