Поделиться через


Расширение окон свойств, списка задач, вывода и параметров

Вы можете получить доступ к любому окну инструментов в Visual Studio. В этом пошаговом руководстве показано, как интегрировать сведения о окне инструментов на новую страницу параметров и новый параметр на странице "Свойства ", а также как записать в окна "Список задач" и "Вывод ".

Создание расширения с окном инструментов

  1. Создайте проект с именем TodoList с помощью шаблона VSIX и добавьте пользовательский шаблон элемента окна инструментов с именем TodoWindow.

    Примечание.

    Дополнительные сведения о создании расширения с помощью окна инструментов см. в разделе "Создание расширения с помощью окна инструментов".

Настройка окна средства

Добавьте текстовое поле, в котором нужно ввести новый элемент ToDo, кнопку, чтобы добавить новый элемент в список, и ListBox для отображения элементов в списке.

  1. В TodoWindow.xaml удалите элементы управления Button, TextBox и StackPanel из UserControl.

    Примечание.

    Это не удаляет обработчик событий button1_Click , который будет повторно использовать на следующем шаге.

  2. В разделе "Все элементы управления WPF" панели элементов перетащите элемент управления Canvas в сетку.

  3. Перетащите текстовое поле, кнопку и listBox на холст. Упорядочение элементов таким образом, чтобы текстовое поле и кнопка были на том же уровне, и ListBox заполняет остальную часть окна под ними, как показано на рисунке ниже.

    Finished Tool Window

  4. На панели 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>
    

Настройка конструктора

  1. В файле TodoWindowControl.xaml.cs добавьте следующую директиву using:

    using System;
    
  2. Добавьте общедоступную ссылку на TodoWindow и конструктор TodoWindowControl принимает параметр TodoWindow. Код должен выглядеть следующим образом:

    public TodoWindow parent;
    
    public TodoWindowControl(TodoWindow window)
    {
        InitializeComponent();
        parent = window;
    }
    
  3. В 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 .

  1. Добавьте класс с именем ToolsOptions.cs. ToolsOptions Сделайте класс наследуемым.DialogPage

    class ToolsOptions : DialogPage
    {
    }
    
  2. Добавьте следующую директиву using:

    using Microsoft.VisualStudio.Shell;
    
  3. Страница "Параметры" в этом пошаговом руководстве предоставляет только один параметр с именем DaysAhead. Добавьте частное поле с именем daysAhead и свойство с именем DaysAhead в ToolsOptions класс:

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

    Теперь необходимо сделать проект осведомленным об этой странице параметров.

Сделать страницу параметров доступной для пользователей

  1. В TodoWindowPackage.cs добавьте в ProvideOptionPageAttribute TodoWindowPackage класс:

    [ProvideOptionPage(typeof(ToolsOptions), "ToDo", "General", 101, 106, true)]
    
  2. Первый параметр конструктора ProvideOptionPage — это тип класса ToolsOptions, созданного ранее. Второй параметр ToDo — это имя категории в диалоговом окне "Параметры ". Третий параметр "Общие" — это имя подкатегории диалогового окна "Параметры ", где будет доступна страница "Параметры". Следующие два параметра — это идентификаторы ресурсов для строк; первое — имя категории, а второй — имя подкатегории. Последний параметр определяет, можно ли получить доступ к этой странице с помощью автоматизации.

    Когда пользователь открывает страницу "Параметры", он должен выглядеть следующим образом.

    Options Page

    Обратите внимание на категорию ToDo и подкатегорию General.

Сделать данные доступными для окно свойств

Сведения о списке toDo можно сделать доступными, создав класс с именем TodoItem , в который хранятся сведения об отдельных элементах в списке ToDo.

  1. Добавьте класс с именем TodoItem.cs.

    Когда окно инструментов доступно для пользователей, элементы в ListBox будут представлены TodoItems. Когда пользователь выбирает один из этих элементов в ListBox, в окне "Свойства " будут отображаться сведения об элементе.

    Чтобы сделать данные доступными в окне "Свойства ", вы преобразуете данные в общедоступные свойства с двумя специальными атрибутами и Description Category. Description — это текст, отображаемый в нижней части окна свойств . Category определяет, где должно отображаться свойство, когда окно "Свойства " отображается в представлении "Категории ". На следующем рисунке окно "Свойства" находится в представлении "Категории", свойство Name в категории "Поля ToDo" выбрано, а описание свойства Name отображается в нижней части окна.

    Properties Window

  2. Добавьте следующие директивы using в файл TodoItem.cs .

    using System.ComponentModel;
    using System.Windows.Forms;
    using Microsoft.VisualStudio.Shell.Interop;
    
  3. 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();
            }
        }
    }
    
  4. Добавьте частную ссылку на элемент управления пользователем. Добавьте конструктор, который принимает элемент управления пользователем и имя этого элемента 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);
    }
    
  5. Так как экземпляры TodoItem класса будут храниться в ListBox, а ListBox вызовет функцию ToString , необходимо перегрузить ToString функцию. Добавьте следующий код в TodoItem.cs после конструктора и до конца класса.

    public override string ToString()
    {
        return name + " Due: " + dueDate.ToShortDateString();
    }
    
  6. В TodoWindowControl.xaml.cs добавьте методы заглушки в TodoWindowControl класс для CheckForError и UpdateList методов. Поместите их после ProcessDialogChar и до конца файла.

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

    Метод CheckForError вызовет метод, имеющий то же имя в родительском объекте, и этот метод будет проверка, произошли ли какие-либо ошибки и обрабатывать их правильно. Метод UpdateList обновит ListBox в родительском элементе управления; метод вызывается при Name DueDate изменении свойств этого класса. Они будут реализованы позже.

Интеграция с окно свойств

Теперь напишите код, который управляет ListBox, который будет привязан к окну свойств .

Необходимо изменить обработчик нажатия кнопки, чтобы прочитать TextBox, создать TodoItem и добавить его в ListBox.

  1. Замените существующую 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();
        }
    }
    
  2. В представлении конструктора выберите элемент управления ListBox. В окне "Свойства" нажмите кнопку обработчиков событий и найдите событие SelectionChanged. Заполните текстовое поле listBox_SelectionChanged. При этом добавляет заглушку для обработчика SelectionChanged и назначает его событию.

  3. Реализуйте метод TrackSelection(). Так как вам потребуется получить SVsUIShellSTrackSelection службы, необходимо сделать GetService доступ к TodoWindowControl. Добавьте приведенный ниже метод в класс TodoWindow:

    internal object GetVsService(Type service)
    {
        return GetService(service);
    }
    
  4. Добавьте следующие директивы using в TodoWindowControl.xaml.cs:

    using System.Runtime.InteropServices;
    using Microsoft.VisualStudio.Shell.Interop;
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.Shell;
    
  5. Заполните обработчик SelectionChanged следующим образом:

    private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        TrackSelection();
    }
    
  6. Теперь заполните функцию 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 в окне свойств , необходимо обновить связанный элемент.

  7. Теперь добавьте остальную часть кода функции 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;
    }
    
  8. Проверьте код. Выполните сборку решения и запустите отладку. Должен появиться экспериментальный экземпляр.

  9. Откройте страницу "Параметры инструментов>". В левой области должна появиться категория ToDo. Категории перечислены в алфавитном порядке, поэтому посмотрите под Ts.

  10. На странице параметров todo должно отобразиться DaysAhead значение 0 свойства. Измените его на 2.

  11. В меню "Вид" или "Другие окна" откройте TodoWindow. Введите endDate в текстовом поле и нажмите кнопку "Добавить".

  12. В списке вы увидите дату через два дня, чем сегодня.

Добавление текста в окно вывода и элементов в список задач

Для списка задач создается новый объект типа Task, а затем добавьте этот объект task в список задач путем вызова его Add метода. Чтобы записать в окно вывода , вызовите его GetPane метод для получения объекта области, а затем вызываете OutputString метод объекта панели.

  1. В файле 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();
        }
    }
    
  2. Чтобы добавить элементы в список задач, необходимо добавить вложенный класс в класс TodoWindowControl. Вложенный класс должен быть производным от TaskProvider. Добавьте следующий код в конец TodoWindowControl класса.

    [Guid("72de1eAD-a00c-4f57-bff7-57edb162d0be")]
    public class TodoWindowTaskProvider : TaskProvider
    {
        public TodoWindowTaskProvider(IServiceProvider sp)
            : base(sp)
        {
        }
    }
    
  3. Затем добавьте частную ссылку на TodoTaskProvider класс и CreateProvider() метод TodoWindowControl . Код должен выглядеть следующим образом:

    private TodoWindowTaskProvider taskProvider;
    private void CreateProvider()
    {
        if (taskProvider == null)
        {
            taskProvider = new TodoWindowTaskProvider(parent);
            taskProvider.ProviderName = "To Do";
        }
    }
    
  4. Добавление 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);
    }
    
  5. Теперь реализуйте 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());
            }
        }
    }
    

Попробуйте

  1. Выполните сборку решения и запустите отладку. Откроется экспериментальный экземпляр.

  2. Откройте TodoWindow (просмотр>других окон>TodoWindow).

  3. Введите что-то в текстовом поле и нажмите кнопку "Добавить".

    Дата выполнения через 2 дня после того, как сегодня будет добавлена в поле списка. Ошибки не создаются, а список задач (просмотр>списка задач) не должен содержать записей.

  4. Теперь измените параметр на странице "Параметры>инструментов>" с 2 обратно на 0.

  5. Введите что-то другое в TodoWindow и нажмите кнопку "Добавить еще раз". Это вызывает ошибку, а также запись в списке задач.

    При добавлении элементов начальная дата установлена плюс 2 дня.

  6. В меню "Вид" щелкните "Выходные данные", чтобы открыть окно вывода.

    Обратите внимание, что при каждом добавлении элемента в области списка задач отображается сообщение.

  7. Щелкните один из элементов в ListBox.

    В окне "Свойства" отображаются два свойства элемента.

  8. Измените одно из свойств и нажмите клавишу ВВОД.

    Элемент обновляется в ListBox.