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
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.
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.
Na seção Todos os Controles WPF da Caixa de Ferramentas, arraste um controle Canvas para a grade.
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.
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
No arquivo TodoWindowControl.xaml.cs adicione a seguinte diretiva using:
using System;
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; }
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.
Adicione uma classe chamada
ToolsOptions.cs
. Faça aToolsOptions
classe herdar de DialogPage.class ToolsOptions : DialogPage { }
Adicione a seguinte diretiva de uso:
using Microsoft.VisualStudio.Shell;
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
Em TodoWindowPackage.cs, adicione um ProvideOptionPageAttribute à
TodoWindowPackage
classe:[ProvideOptionPage(typeof(ToolsOptions), "ToDo", "General", 101, 106, true)]
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.
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.
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 eCategory
.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.Adicione o seguinte usando diretivas o arquivo TodoItem.cs .
using System.ComponentModel; using System.Windows.Forms; using Microsoft.VisualStudio.Shell.Interop;
Adicione o
public
modificador de acesso à declaração de classe.public class TodoItem { }
Adicione as duas propriedades
Name
eDueDate
. Faremos oUpdateList()
eCheckForErrors()
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(); } } }
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); }
Como as
TodoItem
instâncias da classe serão armazenadas no ListBox e o ListBox chamará a função, você deve sobrecarregar aToString
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(); }
Em TodoWindowControl.xaml.cs, adicione métodos stub à
TodoWindowControl
classe para osCheckForError
métodos eUpdateList
. 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. OUpdateList
método atualizará o ListBox no controle pai, o método é chamado quando as propriedades eDueDate
nessaName
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.
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(); } }
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.
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 à classeTodoWindow
:internal object GetVsService(Type service) { return GetService(service); }
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;
Preencha o manipulador SelectionChanged da seguinte maneira:
private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { TrackSelection(); }
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.
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; }
Teste seu código. Compile o projeto e comece a depuração. A instância experimental deve aparecer.
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.
Na página Opções de todo , você deve ver a
DaysAhead
propriedade definida como 0. Mude-o para 2.No menu Exibir / Outro Windows, abra TodoWindow. Digite EndDate na caixa de texto e clique em Adicionar.
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.
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(); } }
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) { } }
Em seguida, adicione uma referência privada e
TodoTaskProvider
umCreateProvider()
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"; } }
Adicione
ClearError()
, que limpa a Lista de Tarefas eReportError()
, 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); }
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
Compile o projeto e comece a depuração. A instância experimental é exibida.
Abra o TodoWindow (Exibir>outro>Windows TodoWindow).
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.
Agora altere a configuração na página Opções>de Ferramentas>ToDo de 2 para 0.
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.
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.
Clique em um dos itens na ListBox.
A janela Propriedades exibe as duas propriedades do item.
Altere uma das propriedades e pressione Enter.
O item é atualizado na ListBox.