Расширение окон свойств, списка задач, вывода и параметров
Вы можете получить доступ к любому окну инструментов в Visual Studio. В этом пошаговом руководстве показано, как интегрировать сведения о окне инструментов на новую страницу параметров и новый параметр на странице "Свойства ", а также как записать в окна "Список задач" и "Вывод ".
Создание расширения с окном инструментов
Создайте проект с именем TodoList с помощью шаблона VSIX и добавьте пользовательский шаблон элемента окна инструментов с именем TodoWindow.
Примечание.
Дополнительные сведения о создании расширения с помощью окна инструментов см. в разделе "Создание расширения с помощью окна инструментов".
Настройка окна средства
Добавьте текстовое поле, в котором нужно ввести новый элемент ToDo, кнопку, чтобы добавить новый элемент в список, и ListBox для отображения элементов в списке.
В TodoWindow.xaml удалите элементы управления Button, TextBox и StackPanel из UserControl.
Примечание.
Это не удаляет обработчик событий button1_Click , который будет повторно использовать на следующем шаге.
В разделе "Все элементы управления WPF" панели элементов перетащите элемент управления Canvas в сетку.
Перетащите текстовое поле, кнопку и listBox на холст. Упорядочение элементов таким образом, чтобы текстовое поле и кнопка были на том же уровне, и ListBox заполняет остальную часть окна под ними, как показано на рисунке ниже.
На панели XAML найдите кнопку и задайте для свойства Content значение Add. Повторно подключите обработчик событий кнопки к элементу управления Button, добавив
Click="button1_Click"
атрибут. Блок Canvas должен выглядеть следующим образом:<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>
Настройка конструктора
В файле TodoWindowControl.xaml.cs добавьте следующую директиву using:
using System;
Добавьте общедоступную ссылку на TodoWindow и конструктор TodoWindowControl принимает параметр TodoWindow. Код должен выглядеть следующим образом:
public TodoWindow parent; public TodoWindowControl(TodoWindow window) { InitializeComponent(); parent = window; }
В TodoWindow.cs измените конструктор TodoWindowControl, чтобы включить параметр TodoWindow. Код должен выглядеть следующим образом:
public TodoWindow() : base(null) { this.Caption = "TodoWindow"; this.BitmapResourceID = 301; this.BitmapIndex = 1; this.Content = new TodoWindowControl(this); }
Создание страницы параметров
Вы можете указать страницу в диалоговом окне "Параметры ", чтобы пользователи могли изменять параметры окна инструментов. Для создания страницы "Параметры" требуется класс, описывающий параметры и запись в файле TodoListPackage.cs или TodoListPackage.vb .
Добавьте класс с именем
ToolsOptions.cs
.ToolsOptions
Сделайте класс наследуемым.DialogPageclass ToolsOptions : DialogPage { }
Добавьте следующую директиву using:
using Microsoft.VisualStudio.Shell;
Страница "Параметры" в этом пошаговом руководстве предоставляет только один параметр с именем DaysAhead. Добавьте частное поле с именем daysAhead и свойство с именем DaysAhead в
ToolsOptions
класс:private double daysAhead; public double DaysAhead { get { return daysAhead; } set { daysAhead = value; } }
Теперь необходимо сделать проект осведомленным об этой странице параметров.
Сделать страницу параметров доступной для пользователей
В TodoWindowPackage.cs добавьте в ProvideOptionPageAttribute
TodoWindowPackage
класс:[ProvideOptionPage(typeof(ToolsOptions), "ToDo", "General", 101, 106, true)]
Первый параметр конструктора ProvideOptionPage — это тип класса
ToolsOptions
, созданного ранее. Второй параметр ToDo — это имя категории в диалоговом окне "Параметры ". Третий параметр "Общие" — это имя подкатегории диалогового окна "Параметры ", где будет доступна страница "Параметры". Следующие два параметра — это идентификаторы ресурсов для строк; первое — имя категории, а второй — имя подкатегории. Последний параметр определяет, можно ли получить доступ к этой странице с помощью автоматизации.Когда пользователь открывает страницу "Параметры", он должен выглядеть следующим образом.
Обратите внимание на категорию ToDo и подкатегорию General.
Сделать данные доступными для окно свойств
Сведения о списке toDo можно сделать доступными, создав класс с именем TodoItem
, в который хранятся сведения об отдельных элементах в списке ToDo.
Добавьте класс с именем
TodoItem.cs
.Когда окно инструментов доступно для пользователей, элементы в ListBox будут представлены TodoItems. Когда пользователь выбирает один из этих элементов в ListBox, в окне "Свойства " будут отображаться сведения об элементе.
Чтобы сделать данные доступными в окне "Свойства ", вы преобразуете данные в общедоступные свойства с двумя специальными атрибутами и
Description
Category
.Description
— это текст, отображаемый в нижней части окна свойств .Category
определяет, где должно отображаться свойство, когда окно "Свойства " отображается в представлении "Категории ". На следующем рисунке окно "Свойства" находится в представлении "Категории", свойство Name в категории "Поля ToDo" выбрано, а описание свойства Name отображается в нижней части окна.Добавьте следующие директивы using в файл TodoItem.cs .
using System.ComponentModel; using System.Windows.Forms; using Microsoft.VisualStudio.Shell.Interop;
public
Добавьте модификатор доступа в объявление класса.public class TodoItem { }
Добавьте два свойства
Name
иDueDate
. Мы сделаем этоUpdateList()
иCheckForErrors()
позже.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(); } } }
Добавьте частную ссылку на элемент управления пользователем. Добавьте конструктор, который принимает элемент управления пользователем и имя этого элемента ToDo. Чтобы найти значение для
daysAhead
, получает свойство страницы "Параметры".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); }
Так как экземпляры
TodoItem
класса будут храниться в ListBox, а ListBox вызовет функциюToString
, необходимо перегрузитьToString
функцию. Добавьте следующий код в TodoItem.cs после конструктора и до конца класса.public override string ToString() { return name + " Due: " + dueDate.ToShortDateString(); }
В TodoWindowControl.xaml.cs добавьте методы заглушки в
TodoWindowControl
класс дляCheckForError
иUpdateList
методов. Поместите их после ProcessDialogChar и до конца файла.public void CheckForErrors() { } public void UpdateList(TodoItem item) { }
Метод
CheckForError
вызовет метод, имеющий то же имя в родительском объекте, и этот метод будет проверка, произошли ли какие-либо ошибки и обрабатывать их правильно. МетодUpdateList
обновит ListBox в родительском элементе управления; метод вызывается приName
DueDate
изменении свойств этого класса. Они будут реализованы позже.
Интеграция с окно свойств
Теперь напишите код, который управляет ListBox, который будет привязан к окну свойств .
Необходимо изменить обработчик нажатия кнопки, чтобы прочитать TextBox, создать TodoItem и добавить его в ListBox.
Замените существующую
button1_Click
функцию кодом, который создает новый TodoItem и добавляет его в ListBox. Он вызываетTrackSelection()
, который будет определен позже.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(); } }
В представлении конструктора выберите элемент управления ListBox. В окне "Свойства" нажмите кнопку обработчиков событий и найдите событие SelectionChanged. Заполните текстовое поле listBox_SelectionChanged. При этом добавляет заглушку для обработчика SelectionChanged и назначает его событию.
Реализуйте метод
TrackSelection()
. Так как вам потребуется получить SVsUIShellSTrackSelection службы, необходимо сделать GetService доступ к TodoWindowControl. Добавьте приведенный ниже метод в классTodoWindow
:internal object GetVsService(Type service) { return GetService(service); }
Добавьте следующие директивы using в TodoWindowControl.xaml.cs:
using System.Runtime.InteropServices; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell;
Заполните обработчик SelectionChanged следующим образом:
private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { TrackSelection(); }
Теперь заполните функцию TrackSelection, которая обеспечит интеграцию с окном "Свойства ". Эта функция вызывается, когда пользователь добавляет элемент в ListBox или щелкает элемент в ListBox. Он добавляет содержимое ListBox в selectionContainer и передает selectionContainer обработчику событий окна OnSelectChange свойств. Служба TrackSelection отслеживает выбранные объекты в пользовательском интерфейсе и отображает их свойства
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); } }
Теперь, когда у вас есть класс, который можно использовать в окне "Свойства", можно интегрировать окно "Свойства" с окном инструментов. Когда пользователь щелкает элемент в listBox в окне инструмента, окно свойств должно быть обновлено соответствующим образом. Аналогичным образом, когда пользователь изменяет элемент ToDo в окне свойств , необходимо обновить связанный элемент.
Теперь добавьте остальную часть кода функции UpdateList в TodoWindowControl.xaml.cs. Он должен удалить и повторно добавить измененный TodoItem из ListBox.
public void UpdateList(TodoItem item) { var index = listBox.SelectedIndex; listBox.Items.RemoveAt(index); listBox.Items.Insert(index, item); listBox.SelectedItem = index; }
Проверьте код. Выполните сборку решения и запустите отладку. Должен появиться экспериментальный экземпляр.
Откройте страницу "Параметры инструментов>". В левой области должна появиться категория ToDo. Категории перечислены в алфавитном порядке, поэтому посмотрите под Ts.
На странице параметров todo должно отобразиться
DaysAhead
значение 0 свойства. Измените его на 2.В меню "Вид" или "Другие окна" откройте TodoWindow. Введите endDate в текстовом поле и нажмите кнопку "Добавить".
В списке вы увидите дату через два дня, чем сегодня.
Добавление текста в окно вывода и элементов в список задач
Для списка задач создается новый объект типа Task, а затем добавьте этот объект task в список задач путем вызова его Add
метода. Чтобы записать в окно вывода , вызовите его GetPane
метод для получения объекта области, а затем вызываете OutputString
метод объекта панели.
В файле TodoWindowControl.xaml.cs в методе
button1_Click
добавьте код, чтобы получить область "Общие" окна вывода (по умолчанию) и напишите в него. Метод будет выглядеть так: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(); } }
Чтобы добавить элементы в список задач, необходимо добавить вложенный класс в класс TodoWindowControl. Вложенный класс должен быть производным от TaskProvider. Добавьте следующий код в конец
TodoWindowControl
класса.[Guid("72de1eAD-a00c-4f57-bff7-57edb162d0be")] public class TodoWindowTaskProvider : TaskProvider { public TodoWindowTaskProvider(IServiceProvider sp) : base(sp) { } }
Затем добавьте частную ссылку на
TodoTaskProvider
класс иCreateProvider()
методTodoWindowControl
. Код должен выглядеть следующим образом:private TodoWindowTaskProvider taskProvider; private void CreateProvider() { if (taskProvider == null) { taskProvider = new TodoWindowTaskProvider(parent); taskProvider.ProviderName = "To Do"; } }
Добавление
ClearError()
, которое очищает список задач иReportError()
добавляет запись в список задач вTodoWindowControl
класс.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); }
Теперь реализуйте
CheckForErrors
метод, как показано ниже.public void CheckForErrors() { foreach (TodoItem item in listBox.Items) { if (item.DueDate < DateTime.Now) { ReportError("To Do Item is out of date: " + item.ToString()); } } }
Попробуйте
Выполните сборку решения и запустите отладку. Откроется экспериментальный экземпляр.
Откройте TodoWindow (просмотр>других окон>TodoWindow).
Введите что-то в текстовом поле и нажмите кнопку "Добавить".
Дата выполнения через 2 дня после того, как сегодня будет добавлена в поле списка. Ошибки не создаются, а список задач (просмотр>списка задач) не должен содержать записей.
Теперь измените параметр на странице "Параметры>инструментов>" с 2 обратно на 0.
Введите что-то другое в TodoWindow и нажмите кнопку "Добавить еще раз". Это вызывает ошибку, а также запись в списке задач.
При добавлении элементов начальная дата установлена плюс 2 дня.
В меню "Вид" щелкните "Выходные данные", чтобы открыть окно вывода.
Обратите внимание, что при каждом добавлении элемента в области списка задач отображается сообщение.
Щелкните один из элементов в ListBox.
В окне "Свойства" отображаются два свойства элемента.
Измените одно из свойств и нажмите клавишу ВВОД.
Элемент обновляется в ListBox.