Procédure pas à pas : Créer un ornement de vue, les commandes et paramètres (repères de colonne)Walkthrough: Create a view adornment, commands, and settings (column guides)

Vous pouvez étendre l’éditeur de texte/code de Visual Studio avec les commandes et les effets de la vue.You can extend the Visual Studio text/code editor with commands and view effects. Cet article vous montre comment commencer avec une fonctionnalité d’extension populaire, repères de colonne.This article shows you how to get started with a popular extension feature, column guides. Repères de colonne sont visuellement clair lignes dessinées sur la vue de l’éditeur de texte pour vous aider à gérer votre code pour les largeurs de colonne spécifique.Column guides are visually light lines drawn on the text editor's view to help you manage your code to specific column widths. Plus précisément, le code mis en forme peut être important pour obtenir des exemples d’inclure dans les documents, les billets de blog, ou de rapports de bogues.Specifically, formatted code can be important for samples you include in documents, blog posts, or bug reports.

Dans cette procédure pas à pas, vous :In this walkthrough, you:

  • Créez un projet VSIXCreate a VSIX project

  • Ajouter un ornement de vue de l’éditeurAdd an editor view adornment

  • Ajouter la prise en charge pour l’enregistrement et l’obtention des paramètres (où pour dessiner les repères de colonne et leur couleur)Add support for saving and getting settings (where to draw column guides and their color)

  • Ajouter des commandes (Ajouter/supprimer des repères de colonne, modifier leur couleur)Add commands (add/remove column guides, change their color)

  • Placez les commandes du menu Edition et les menus contextuels de document textePlace the commands on the Edit menu and text document context menus

  • Ajouter la prise en charge pour appeler les commandes à partir de la fenêtre de commande Visual StudioAdd support for invoking the commands from the Visual Studio Command Window

    Vous pouvez essayer une version de la fonctionnalité de repères de colonne avec cette galerie Visual Studioextension.You can try out a version of the column guides feature with this Visual Studio Galleryextension.

    Remarque: dans cette procédure pas à pas, vous collez une grande quantité de code dans quelques fichiers générés par les modèles d’extension de Visual Studio.NOTE: In this walkthrough, you paste a great amount of code into a few files generated by Visual Studio extension templates. Toutefois, dès cette procédure pas à pas fait référence à une solution terminée sur github avec d’autres exemples d’extension.But, soon this walkthrough will refer to a completed solution on github with other extension examples. Le code complet est légèrement différent car il a des icônes de commande réelles au lieu d’utiliser des icônes de generictemplate.The completed code is slightly different in that it has real command icons instead of using generictemplate icons.

Prise en mainGet started

À partir de Visual Studio 2015, vous n’installez pas le Kit de développement logiciel Visual Studio à partir du centre de téléchargement.Starting in Visual Studio 2015, you do not install the Visual Studio SDK from the download center. Il est inclus comme fonctionnalité facultative dans le programme d’installation de Visual Studio.It's included as an optional feature in Visual Studio setup. Vous pouvez également installer le kit SDK VS par la suite.You can also install the VS SDK later on. Pour plus d’informations, consultez installer le SDK Visual Studio.For more information, see Install the Visual Studio SDK.

Configurer la solutionSet up the solution

Tout d’abord, vous créez un projet VSIX, ajoutez un ornement de vue de l’éditeur, puis ajoutez une commande (qui ajoute un VSPackage doit détenir la commande).First, you create a VSIX project, add an editor view adornment, and then add a command (which adds a VSPackage to own the command). L’architecture de base est la suivante :The basic architecture is as follows:

  • Vous avez un écouteur de la création de vue de texte qui crée un ColumnGuideAdornment objet par la vue.You have a text view creation listener that creates a ColumnGuideAdornment object per view. Cet objet écoute les événements sur la modification de la vue ou les repères de colonne de la mise à jour ou écran Paramètres de modification, en fonction des besoins.This object listens for events about the view changing or settings changing, updating or redrawing column guides as necessary.

  • Il existe un GuidesSettingsManager qui gère la lecture et écriture à partir du stockage de paramètres de Visual Studio.There's a GuidesSettingsManager that handles reading and writing from the Visual Studio settings storage. Le Gestionnaire de paramètres a également des opérations pour la mise à jour les paramètres qui prennent en charge les commandes de l’utilisateur (ajouter une colonne, supprimez la colonne, modifier la couleur).The settings manager also has operations for updating the settings that support the user commands (add column, remove column, change color).

  • Il existe un package VSIP qui est nécessaire si vous avez des commandes de l’utilisateur, mais il est simplement un code réutilisable qui initialise l’objet d’implémentation de commandes.There's a VSIP package that's necessary if you have user commands, but it's just boilerplate code that initializes the commands implementation object.

  • Il existe un ColumnGuideCommands objet qui s’exécute à l’utilisateur des commandes et raccorde les gestionnaires de commandes pour les commandes déclarées dans le .vsct fichier.There's a ColumnGuideCommands object that runs the user commands and hooks up the command handlers for commands declared in the .vsct file.

    VSIX.VSIX. Utilisez fichier | nouveau... commande pour créer un projet.Use File | New ... command to create a project. Choisissez le extensibilité nœud sous c# dans le volet de navigation de gauche et choisissez projet VSIX dans le volet droit.Choose the Extensibility node under C# in the left navigation pane and choose VSIX Project in the right pane. Entrez le nom ColumnGuides et choisissez OK pour créer le projet.Enter the name ColumnGuides and choose OK to create the project.

    Afficher les ornements.View adornment. Appuyez sur le bouton droit du pointeur sur le nœud de projet dans l’Explorateur de solutions.Press the right pointer button on the project node in the Solution Explorer. Choisissez le ajouter | un nouvel élément... commande pour ajouter un nouvel élément d’ornement de vue.Choose the Add | New Item ... command to add a new view adornment item. Choisissez extensibilité | éditeur dans le volet de navigation de gauche et choisissez ornement de la fenêtre d’affichage de l’éditeur dans le volet droit.Choose Extensibility | Editor in the left navigation pane and choose Editor Viewport Adornment in the right pane. Entrez le nom ColumnGuideAdornment en tant que l’élément de nom et choisissez ajouter pour l’ajouter.Enter the name ColumnGuideAdornment as the item name and choose Add to add it.

    Vous pouvez voir ce modèle d’élément ajouté deux fichiers au projet (ainsi que les références et ainsi de suite) : ColumnGuideAdornment.cs et ColumnGuideAdornmentTextViewCreationListener.cs.You can see this item template added two files to the project (as well as references, and so on): ColumnGuideAdornment.cs and ColumnGuideAdornmentTextViewCreationListener.cs. Les modèles de dessiner un rectangle violet sur la vue.The templates draw a purple rectangle on the view. Dans la section suivante, vous modifiez quelques lignes dans l’écouteur de la création de vue et remplacez le contenu de ColumnGuideAdornment.cs.In the following section, you change a couple of lines in the view creation listener and replace the contents of ColumnGuideAdornment.cs.

    Commandes.Commands. Dans l’Explorateur de solutions, appuyez sur le bouton droit du pointeur sur le nœud du projet.In Solution Explorer, press the right pointer button on the project node. Choisissez le ajouter | un nouvel élément... commande pour ajouter un nouvel élément d’ornement de vue.Choose the Add | New Item ... command to add a new view adornment item. Choisissez extensibilité | VSPackage dans le volet de navigation de gauche et choisissez commande personnalisée dans le volet droit.Choose Extensibility | VSPackage in the left navigation pane and choose Custom Command in the right pane. Entrez le nom ColumnGuideCommands en tant que l’élément de nom et choisissez ajouter.Enter the name ColumnGuideCommands as the item name and choose Add. En plus de plusieurs références, ajout des commandes et package également ajouté ColumnGuideCommands.cs, ColumnGuideCommandsPackage.cs, et ColumnGuideCommandsPackage.vsct .In addition to several references, adding the commands and package also added ColumnGuideCommands.cs, ColumnGuideCommandsPackage.cs, and ColumnGuideCommandsPackage.vsct. Dans la section suivante, vous remplacez le contenu des premier et derniers fichiers pour définir et implémenter les commandes.In the following section, you replace the contents of first and last files to define and implement the commands.

Configurer l’écouteur de la création de vue de texteSet up the text view creation listener

Ouvrez ColumnGuideAdornmentTextViewCreationListener.cs dans l’éditeur.Open ColumnGuideAdornmentTextViewCreationListener.cs in the editor. Ce code implémente un gestionnaire pour chaque fois que Visual Studio crée des affichages de texte.This code implements a handler for whenever Visual Studio creates text views. Il existe des attributs qui contrôlent la lorsque le gestionnaire est appelé en fonction des caractéristiques de la vue.There are attributes that control when the handler is called depending on characteristics of the view.

Le code doit également déclarer une couche d’ornement.The code also must declare an adornment layer. Lorsque l’éditeur met à jour les vues, il obtient les couches d’ornement pour l’affichage et à partir de qui obtient les éléments d’ornement.When the editor updates views, it gets the adornment layers for the view and from that gets the adornment elements. Vous pouvez déclarer le classement de votre couche par rapport à d’autres attributs.You can declare the ordering of your layer relative to others with attributes. Remplacez la ligne suivante :Replace the following line:

[Order(After = PredefinedAdornmentLayers.Caret)]  

avec ces deux lignes :with these two lines:

[Order(Before = PredefinedAdornmentLayers.Text)]  
[TextViewRole(PredefinedTextViewRoles.Document)]  

La ligne que vous avez remplacé est dans un groupe d’attributs qui déclarent une couche d’ornement.The line you replaced is in a group of attributes that declare an adornment layer. La première ligne que vous avez modifié dans lequel les lignes de repère de colonne s’affichent uniquement les modifications.The first line you changed only changes where the column guide lines appear. Les lignes de dessin « avant » le texte dans la vue signifie qu’ils apparaissent derrière ou en dessous du texte.Drawing the lines "before" the text in the view means they appear behind or below the text. La deuxième ligne déclare que les ornements de guide de colonne sont applicables aux entités de texte qui correspondent à votre notion d’un document, mais vous pouvez déclarer l’ornement, par exemple, pour seulement le travail pour le texte modifiable.The second line declares that the column guide adornments are applicable to text entities that fit your notion of a document, but you could declare the adornment, for example, to only work for editable text. Il existe plus d’informations dans points d’extension éditeur et le service de langageThere's more information in Language service and editor extension points

Implémenter le Gestionnaire de paramètresImplement the settings manager

Remplacez le contenu de la GuidesSettingsManager.cs avec le code suivant (voir ci-après) :Replace the contents of the GuidesSettingsManager.cs with the following code (explained below):

using Microsoft.VisualStudio.Settings;  
using Microsoft.VisualStudio.Shell;  
using Microsoft.VisualStudio.Shell.Settings;  
using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Windows.Media;  

namespace ColumnGuides  
{  
    internal static class GuidesSettingsManager  
    {  
        // Because my code is always called from the UI thred, this succeeds.  
        internal static SettingsManager VsManagedSettingsManager =  
            new ShellSettingsManager(ServiceProvider.GlobalProvider);  

        private const int _maxGuides = 5;  
        private const string _collectionSettingsName = "Text Editor";  
        private const string _settingName = "Guides";  
        // 1000 seems reasonable since primary scenario is long lines of code  
        private const int _maxColumn = 1000;   

        static internal bool AddGuideline(int column)  
        {  
            if (! IsValidColumn(column))  
                throw new ArgumentOutOfRangeException(  
                    "column",  
                    "The paramenter must be between 1 and " + _maxGuides.ToString());  
            var offsets = GuidesSettingsManager.GetColumnOffsets();  
            if (offsets.Count() >= _maxGuides)  
                return false;  
            // Check for duplicates  
            if (offsets.Contains(column))  
                return false;  
            offsets.Add(column);  
            WriteSettings(GuidesSettingsManager.GuidelinesColor, offsets);  
            return true;  
        }  

        static internal bool RemoveGuideline(int column)  
        {  
            if (!IsValidColumn(column))  
                throw new ArgumentOutOfRangeException(  
                    "column", "The paramenter must be between 1 and 10,000");  
            var columns = GuidesSettingsManager.GetColumnOffsets();  
            if (! columns.Remove(column))  
            {  
                // Not present.  Allow user to remove the last column   
                // even if they're not on the right column.  
                if (columns.Count != 1)  
                    return false;  

                columns.Clear();  
            }  
            WriteSettings(GuidesSettingsManager.GuidelinesColor, columns);  
            return true;  
        }  

        static internal bool CanAddGuideline(int column)  
        {  
            if (!IsValidColumn(column))  
                return false;  
            var offsets = GetColumnOffsets();  
            if (offsets.Count >= _maxGuides)  
                return false;  
            return ! offsets.Contains(column);  
        }  

        static internal bool CanRemoveGuideline(int column)  
        {  
            if (! IsValidColumn(column))  
                return false;  
            // Allow user to remove the last guideline regardless of the column.  
            // Okay to call count, we limit the number of guides.  
            var offsets = GuidesSettingsManager.GetColumnOffsets();  
            return offsets.Contains(column) || offsets.Count() == 1;  
        }  

        static internal void RemoveAllGuidelines()  
        {  
            WriteSettings(GuidesSettingsManager.GuidelinesColor, new int[0]);  
        }  

        private static bool IsValidColumn(int column)  
        {  
            // zero is allowed (per user request)  
            return 0 <= column && column <= _maxColumn;  
        }  

        // This has format "RGB(<int>, <int>, <int>) <int> <int>...".  
        // There can be any number of ints following the RGB part,   
        // and each int is a column (char offset into line) where to draw.  
        static private string _guidelinesConfiguration;  
        static private string GuidelinesConfiguration  
        {  
            get  
            {  
                if (_guidelinesConfiguration == null)  
                {  
                    _guidelinesConfiguration =   
                        GetUserSettingsString(  
                            GuidesSettingsManager._collectionSettingsName,  
                            GuidesSettingsManager._settingName)  
                        .Trim();  
                }  
                return _guidelinesConfiguration;  
            }  

            set  
            {  
                if (value != _guidelinesConfiguration)  
                {  
                    _guidelinesConfiguration = value;  
                    WriteUserSettingsString(  
                        GuidesSettingsManager._collectionSettingsName,  
                        GuidesSettingsManager._settingName, value);  
                    // Notify ColumnGuideAdornments to update adornments in views.  
                    var handler = GuidesSettingsManager.SettingsChanged;  
                    if (handler != null)  
                        handler();  
                }  
            }  
        }  

        internal static string GetUserSettingsString(string collection, string setting)  
        {  
            var store = GuidesSettingsManager  
                            .VsManagedSettingsManager  
                            .GetReadOnlySettingsStore(SettingsScope.UserSettings);  
            return store.GetString(collection, setting, "RGB(255,0,0) 80");  
        }  

        internal static void WriteUserSettingsString(string key, string propertyName,  
                                                     string value)  
        {  
            var store = GuidesSettingsManager  
                            .VsManagedSettingsManager  
                            .GetWritableSettingsStore(SettingsScope.UserSettings);  
            store.CreateCollection(key);  
            store.SetString(key, propertyName, value);  
        }  

        // Persists settings and sets property with side effect of signaling  
        // ColumnGuideAdornments to update.  
        static private void WriteSettings(Color color, IEnumerable<int> columns)  
        {  
            string value = ComposeSettingsString(color, columns);  
            GuidelinesConfiguration = value;  
        }  

        private static string ComposeSettingsString(Color color,  
                                                    IEnumerable<int> columns)  
        {  
            StringBuilder sb = new StringBuilder();  
            sb.AppendFormat("RGB({0},{1},{2})", color.R, color.G, color.B);  
            IEnumerator<int> columnsEnumerator = columns.GetEnumerator();  
            if (columnsEnumerator.MoveNext())  
            {  
                sb.AppendFormat(" {0}", columnsEnumerator.Current);  
                while (columnsEnumerator.MoveNext())  
                {  
                    sb.AppendFormat(", {0}", columnsEnumerator.Current);  
                }  
            }  
            return sb.ToString();  
        }  

        // Parse a color out of a string that begins like "RGB(255,0,0)"  
        static internal Color GuidelinesColor  
        {  
            get  
            {  
                string config = GuidelinesConfiguration;  
                if (!String.IsNullOrEmpty(config) && config.StartsWith("RGB("))  
                {  
                    int lastParen = config.IndexOf(')');  
                    if (lastParen > 4)  
                    {  
                        string[] rgbs = config.Substring(4, lastParen - 4).Split(',');  

                        if (rgbs.Length >= 3)  
                        {  
                            byte r, g, b;  
                            if (byte.TryParse(rgbs[0], out r) &&  
                                byte.TryParse(rgbs[1], out g) &&  
                                byte.TryParse(rgbs[2], out b))  
                            {  
                                return Color.FromRgb(r, g, b);  
                            }  
                        }  
                    }  
                }  
                return Colors.DarkRed;  
            }  

            set  
            {  
                WriteSettings(value, GetColumnOffsets());  
            }  
        }  

        // Parse a list of integer values out of a string that looks like  
        // "RGB(255,0,0) 1, 5, 10, 80"  
        static internal List<int> GetColumnOffsets()  
        {  
            var result = new List<int>();  
            string settings = GuidesSettingsManager.GuidelinesConfiguration;  
            if (String.IsNullOrEmpty(settings))  
                return new List<int>();  

            if (!settings.StartsWith("RGB("))  
                return new List<int>();  

            int lastParen = settings.IndexOf(')');  
            if (lastParen <= 4)  
                return new List<int>();  

            string[] columns = settings.Substring(lastParen + 1).Split(',');  

            int columnCount = 0;  
            foreach (string columnText in columns)  
            {  
                int column = -1;  
                // VS 2008 gallery extension didn't allow zero, so per user request ...  
                if (int.TryParse(columnText, out column) && column >= 0)  
                {  
                    columnCount++;  
                    result.Add(column);  
                    if (columnCount >= _maxGuides)  
                        break;  
                }  
            }  
            return result;  
        }  

        // Delegate and Event to fire when settings change so that ColumnGuideAdornments   
        // can update.  We need nothing special in this event since the settings manager   
        // is statically available.  
        //  
        internal delegate void SettingsChangedHandler();  
        static internal event SettingsChangedHandler SettingsChanged;  

    }  
}  

La majeure partie de ce code crée et analyse le format de paramètres : « RVB (<int >,<int >,<int >) <int >, <int >,... ».Most of this code creates and parses the settings format: "RGB(<int>,<int>,<int>) <int>, <int>, ...". Les entiers à la fin sont les colonnes en fonction de celui où vous souhaitez les repères de colonne.The integers at the end are the one-based columns where you want column guides. L’extension de repères de colonne capture tous ses paramètres dans une chaîne de valeur de paramètre unique.The column guides extension captures all its settings in a single setting value string.

Il existe certaines parties du code intéressant.There are some parts of the code worth highlighting. La ligne de code suivante obtient le wrapper managé Visual Studio pour le stockage des paramètres.The following line of code gets the Visual Studio managed wrapper for the settings storage. Pour l’essentiel, Ceci extrait sur le Registre Windows, mais cette API est indépendante du mécanisme de stockage.For the most part, this abstracts over the Windows registry, but this API is independent of the storage mechanism.

internal static SettingsManager VsManagedSettingsManager =  
    new ShellSettingsManager(ServiceProvider.GlobalProvider);  

Le stockage des paramètres Visual Studio utilise un identificateur de catégorie et un identificateur de paramètre pour identifier tous les paramètres :The Visual Studio settings storage uses a category identifier and a setting identifier to uniquely identify all settings:

private const string _collectionSettingsName = "Text Editor";  
private const string _settingName = "Guides";  

Il est inutile d’utiliser "Text Editor" comme nom de catégorie.You do not have to use "Text Editor" as the category name. Vous pouvez choisir comme vous le souhaitez.You can pick anything you like.

Les quelques premières fonctions sont les points d’entrée pour modifier les paramètres.The first few functions are the entry points to change settings. Ils vérifient les contraintes de haut niveau comme nombre maximal de guides autorisé.They check high-level constraints like maximum number of guides allowed. Ensuite, ils appellent WriteSettings, ce qui constitue une chaîne de paramètres et définit la propriété GuideLinesConfiguration.Then, they call WriteSettings, which composes a settings string and sets the property GuideLinesConfiguration. Définition de cette propriété enregistre la valeur de paramètres pour la banque de paramètres de Visual Studio et se déclenche le SettingsChanged événement à mettre à jour tous les ColumnGuideAdornment objets, chacun étant associé à un affichage de texte.Setting this property saves the settings value to the Visual Studio settings store and fires the SettingsChanged event to update all the ColumnGuideAdornment objects, each associated with a text view.

Il existe quelques fonctions de point d’entrée, tel que CanAddGuideline, qui sont utilisées pour implémenter les commandes qui modifient les paramètres.There are a couple of entry point functions, such as CanAddGuideline, which are used to implement commands that change settings. Lorsque Visual Studio affiche des menus, il interroge les implémentations de commande pour voir si la commande est actuellement activée, ce qui est son nom et ainsi de suite.When Visual Studio shows menus, it queries command implementations to see if the command is currently enabled, what its name is, and so on. Ci-dessous, vous allez apprendre à raccorder à ces points d’entrée pour les implémentations de commandes.Below you see how to hook up these entry points for the command implementations. Pour plus d’informations sur les commandes, consultez étendre des menus et commandes.For more information on commands, see Extend menus and commands.

Implémentez la classe ColumnGuideAdornmentImplement the ColumnGuideAdornment class

Le ColumnGuideAdornment classe est instanciée pour chaque affichage de texte qui peut avoir des ornements.The ColumnGuideAdornment class is instantiated for each text view that can have adornments. Cette classe écoute les événements sur la modification de la vue ou les paramètres de modification et les repères de colonne de la mise à jour ou écran en fonction des besoins.This class listens for events about the view changing or settings changing, and the updating or redrawing column guides as necessary.

Remplacez le contenu de la ColumnGuideAdornment.cs avec le code suivant (voir ci-après) :Replace the contents of the ColumnGuideAdornment.cs with the following code (explained below):

using System;  
using System.Windows.Media;  
using Microsoft.VisualStudio.Text.Editor;  
using System.Collections.Generic;  
using System.Windows.Shapes;  
using Microsoft.VisualStudio.Text.Formatting;  
using System.Windows;  

namespace ColumnGuides  
{  
    /// <summary>  
    /// Adornment class, one instance per text view that draws a guides on the viewport  
    /// </summary>  
    internal sealed class ColumnGuideAdornment  
    {  
        private const double _lineThickness = 1.0;  
        private IList<Line> _guidelines;  
        private IWpfTextView _view;  
        private double _baseIndentation;  
        private double _columnWidth;  

        /// <summary>  
        /// Creates editor column guidelines  
        /// </summary>  
        /// <param name="view">The <see cref="IWpfTextView"/> upon   
        /// which the adornment will be drawn</param>  
        public ColumnGuideAdornment(IWpfTextView view)  
        {  
            _view = view;  
            _guidelines = CreateGuidelines();  
            GuidesSettingsManager.SettingsChanged +=   
                new GuidesSettingsManager.SettingsChangedHandler(SettingsChanged);  
            view.LayoutChanged +=   
                new EventHandler<TextViewLayoutChangedEventArgs>(OnViewLayoutChanged);  
            _view.Closed += new EventHandler(OnViewClosed);  
        }  

        void SettingsChanged()  
        {  
            _guidelines = CreateGuidelines();  
            UpdatePositions();  
            AddGuidelinesToAdornmentLayer();  
        }  

        void OnViewClosed(object sender, EventArgs e)  
        {  
            _view.LayoutChanged -= OnViewLayoutChanged;  
            _view.Closed -= OnViewClosed;  
            GuidesSettingsManager.SettingsChanged -= SettingsChanged;  
        }  

        private bool _firstLayoutDone;  

        void OnViewLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)  
        {  
            bool fUpdatePositions = false;  

            IFormattedLineSource lineSource = _view.FormattedLineSource;  
            if (lineSource == null)  
            {  
                return;  
            }  
            if (_columnWidth != lineSource.ColumnWidth)  
            {  
                _columnWidth = lineSource.ColumnWidth;  
                fUpdatePositions = true;  
            }  
            if (_baseIndentation != lineSource.BaseIndentation)  
            {  
                _baseIndentation = lineSource.BaseIndentation;  
                fUpdatePositions = true;  
            }  
            if (fUpdatePositions ||  
                e.VerticalTranslation ||  
                e.NewViewState.ViewportTop != e.OldViewState.ViewportTop ||  
                e.NewViewState.ViewportBottom != e.OldViewState.ViewportBottom)  
            {  
                UpdatePositions();  
            }  
            if (!_firstLayoutDone)  
            {  
                AddGuidelinesToAdornmentLayer();  
                _firstLayoutDone = true;  
            }  
        }  

        private static IList<Line> CreateGuidelines()  
        {  
            Brush lineBrush = new SolidColorBrush(GuidesSettingsManager.GuidelinesColor);  
            DoubleCollection dashArray = new DoubleCollection(new double[] { 1.0, 3.0 });  
            IList<Line> result = new List<Line>();  
            foreach (int column in GuidesSettingsManager.GetColumnOffsets())  
            {  
                Line line = new Line()  
                {  
                    // Use the DataContext slot as a cookie to hold the column  
                    DataContext = column,  
                    Stroke = lineBrush,  
                    StrokeThickness = _lineThickness,  
                    StrokeDashArray = dashArray  
                };  
                result.Add(line);  
            }  
            return result;  
        }  

        void UpdatePositions()  
        {  
            foreach (Line line in _guidelines)  
            {  
                int column = (int)line.DataContext;  
                line.X2 = _baseIndentation + 0.5 + column * _columnWidth;  
                line.X1 = line.X2;  
                line.Y1 = _view.ViewportTop;  
                line.Y2 = _view.ViewportBottom;  
            }  
        }  

        void AddGuidelinesToAdornmentLayer()  
        {  
            // Grab a reference to the adornment layer that this adornment   
            // should be added to  
            // Must match exported name in ColumnGuideAdornmentTextViewCreationListener  
            IAdornmentLayer adornmentLayer =   
                _view.GetAdornmentLayer("ColumnGuideAdornment");  
            if (adornmentLayer == null)  
                return;  
            adornmentLayer.RemoveAllAdornments();  
            // Add the guidelines to the adornment layer and make them relative   
            // to the viewport  
            foreach (UIElement element in _guidelines)  
                adornmentLayer.AddAdornment(AdornmentPositioningBehavior.OwnerControlled,  
                                            null, null, element, null);  
        }  
    }  

}  

Instances de cette classe contiennent associé IWpfTextView et une liste de Line objets dessinés sur la vue.Instances of this class hold onto the associated IWpfTextView and a list of Line objects drawn on the view.

Le constructeur (appelée à partir de ColumnGuideAdornmentTextViewCreationListener lorsque Visual Studio crée des vues) crée le repère de colonne Line objets.The constructor (called from ColumnGuideAdornmentTextViewCreationListener when Visual Studio creates new views) creates the column guide Line objects. Le constructeur ajoute également des gestionnaires pour les SettingsChanged événement (défini dans GuidesSettingsManager) et les événements d’affichage LayoutChanged et Closed.The constructor also adds handlers for the SettingsChanged event (defined in GuidesSettingsManager) and the view events LayoutChanged and Closed.

Le LayoutChanged événement est déclenché en raison de plusieurs types de modifications dans la vue, y compris lorsque Visual Studio crée la vue.The LayoutChanged event fires due to several kinds of changes in the view, including when Visual Studio creates the view. Le OnViewLayoutChanged appels du gestionnaire AddGuidelinesToAdornmentLayer à exécuter.The OnViewLayoutChanged handler calls AddGuidelinesToAdornmentLayer to execute. Le code dans OnViewLayoutChanged détermine s’il faut mettre à jour les positions de ligne en fonction des modifications telles que les modifications de taille de police, espacement de la vue, le défilement horizontal et ainsi de suite.The code in OnViewLayoutChanged determines if it needs to update line positions based on changes such as font size changes, view gutters, horizontal scrolling, and so on. Le code dans UpdatePositions provoque des lignes de repère dessiner entre caractères ou juste après la colonne de texte qui se trouve dans le décalage de caractère spécifié dans la ligne de texte.The code in UpdatePositions causes guide lines to draw between characters or just after the column of text that is in the specified character offset in the line of text.

Chaque fois que les paramètres changent le SettingsChanged fonction recrée simplement tous le Line objets avec toutes les nouveaux paramètres sont.Whenever settings change the SettingsChanged function just recreates all the Line objects with whatever the new settings are. Après avoir défini les positions de ligne, le code supprime toutes les précédentes Line objets à partir de la ColumnGuideAdornment couche d’ornement et ajoute de nouveaux styles.After setting the line positions, the code removes all previous Line objects from the ColumnGuideAdornment adornment layer and adds the new ones.

Définir des commandes, des menus et des emplacements de menuDefine the commands, menus, and menu placements

Il peut y avoir beaucoup déclarer les menus et commandes mise des groupes de menus ou de commandes sur différents autres menus et la raccorder les gestionnaires de commandes.There can be a lot to declaring commands and menus, placing groups of commands or menus on various other menus, and hooking up command handlers. Cette procédure pas à pas met en évidence le fonctionnement des commandes de cette extension, mais pour des informations plus détaillées, consultez étendre des menus et commandes.This walkthrough highlights how commands work in this extension, but for deeper information, see Extend menus and commands.

Introduction au codeIntroduction to the code

L’extension de repères de colonne illustre la déclaration d’un groupe de commandes qui vont ensemble (ajouter une colonne, supprimez la colonne, modifier la couleur de ligne) et ensuite placer ce groupe sur un sous-menu du menu contextuel de l’éditeur.The Column Guides extension shows declaring a group of commands that belong together (add column, remove column, change line color), and then placing that group on a sub menu of the editor's context menu. L’extension de repères de colonne ajoute également les commandes à la main modifier menu, mais conserve les invisible, présentés comme un modèle courant ci-dessous.The Column Guides extension also adds the commands to the main Edit menu but keeps them invisible, discussed as a common pattern below.

L’implémentation de commandes se compose de trois parties : ColumnGuideCommandsPackage.cs, ColumnGuideCommandsPackage.vsct et ColumnGuideCommands.cs.There are three parts to the commands implementation: ColumnGuideCommandsPackage.cs, ColumnGuideCommandsPackage.vsct, and ColumnGuideCommands.cs. Le code généré par les modèles place une commande sur le outils menu qui s’affiche une boîte de dialogue en tant que l’implémentation.The code generated by the templates puts a command on the Tools menu that pops a dialog box as the implementation. Vous pouvez examiner comment qui est implémenté dans le .vsct et ColumnGuideCommands.cs des fichiers dans la mesure où il est simple.You can look at how that is implemented in the .vsct and ColumnGuideCommands.cs files since it is straightforward. Vous remplacez le code dans ces fichiers ci-dessous.You replace the code in these files below.

Le code du package contient des déclarations réutilisable requises pour Visual Studio de découvrir que l’extension offre des commandes et de trouver où placer les commandes.The package code comtains boilerplate declarations required for Visual Studio to discover that the extension offers commands and to find where to place the commands. Quand le package s’initialise, elle instancie la classe d’implémentation de commandes.When the package initializes, it instantiates the commands implementation class. Pour plus d’informations sur les packages de commandes, consultez étendre des menus et commandes.For more information about packages relating to commands, see Extend menus and commands.

Un modèle courant de commandesA common commands pattern

Les commandes de l’extension de repères de colonne sont un exemple d’un modèle très courant dans Visual Studio.The commands in the Column Guides extension are an example of a very common pattern in Visual Studio. Vous placez les commandes associées dans un groupe, et que vous placez ce groupe dans un menu principal, souvent avec «<CommandFlag>CommandWellOnly</CommandFlag>» définie pour rendre la commande invisible.You put related commands in a group, and you put that group on a main menu, often with "<CommandFlag>CommandWellOnly</CommandFlag>" set to make the command invisible. Placer des commandes sur les menus principaux (tel que modifier) leur donne la personnalisation des noms (tel que Edit.AddColumnGuide), qui sont utile pour identifier les commandes lors de l’affectation des combinaisons de touches dans outils Options.Putting commands on the main menus (such as Edit) gives them nice names (such as Edit.AddColumnGuide), which are useful for finding commands when re-assigning key bindings in Tools Options. Il est également utile pour obtenir la saisie semi-automatique lors de l’appel des commandes à partir de la fenêtre de commande.It's also useful for getting completion when invoking commands from the Command Window.

Vous ajoutez le groupe de commandes aux menus contextuels ou sub où vous prévoyez d’utilisateurs à utiliser les commandes de menus.You then add the group of commands to context menus or sub menus where you expect user to use the commands. Visual Studio traite CommandWellOnly comme un indicateur de l’invisibilité pour les menus principaux uniquement.Visual Studio treats CommandWellOnly as an invisibility flag for main menus only. Lorsque vous placez le même groupe de commandes sur un menu contextuel ou un sous-menu, les commandes sont visibles.When you place the same group of commands on a context menu or sub menu, the commands are visible.

Dans le cadre du modèle commun, l’extension de repères de colonne crée un deuxième groupe qui contient un sous-menu unique.As part of the common pattern, the Column Guides extension creates a second group that holds a single sub menu. Le sous-menu contient à son tour le premier groupe avec les commandes de guide de quatre colonnes.The sub menu in turn contains the first group with the four-column guide commands. Le deuxième groupe qui contient le sous-menu est la ressource réutilisable que vous placez sur différents menus contextuels, qui met un sous-menu sur ces menus contextuels.The second group that holds the sub menu is the reusable asset that you place on various context menus, which puts a sub menu on those context menus.

Le fichier .vsctThe .vsct file

Le .vsct fichier déclare les commandes et où ils aillent, ainsi que des icônes et ainsi de suite.The .vsct file declares the commands and where they go, along with icons and so on. Remplacez le contenu de la .vsct fichier par le code suivant (voir ci-après) :Replace the contents of the .vsct file with the following code (explained below):

<?xml version="1.0" encoding="utf-8"?>  
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">  

  <!--  This is the file that defines the actual layout and type of the commands.  
        It is divided in different sections (e.g. command definition, command  
        placement, ...), with each defining a specific set of properties.  
        See the comment before each section for more details about how to  
        use it. -->  

  <!--  The VSCT compiler (the tool that translates this file into the binary  
        format that VisualStudio will consume) has the ability to run a preprocessor  
        on the vsct file; this preprocessor is (usually) the C++ preprocessor, so  
        it is possible to define includes and macros with the same syntax used  
        in C++ files. Using this ability of the compiler here, we include some files  
        defining some of the constants that we will use inside the file. -->  

  <!--This is the file that defines the IDs for all the commands exposed by   
      VisualStudio. -->  
  <Extern href="stdidcmd.h"/>  

  <!--This header contains the command ids for the menus provided by the shell. -->  
  <Extern href="vsshlids.h"/>  

  <!--The Commands section is where commands, menus, and menu groups are defined.  
      This section uses a Guid to identify the package that provides the command   
      defined inside it. -->  
  <Commands package="guidColumnGuideCommandsPkg">  
    <!-- Inside this section we have different sub-sections: one for the menus, another    
    for the menu groups, one for the buttons (the actual commands), one for the combos   
    and the last one for the bitmaps used. Each element is identified by a command id  
    that is a unique pair of guid and numeric identifier; the guid part of the identifier  
    is usually called "command set" and is used to group different command inside a  
    logically related group; your package should define its own command set in order to  
    avoid collisions with command ids defined by other packages. -->  

    <!-- In this section you can define new menu groups. A menu group is a container for   
         other menus or buttons (commands); from a visual point of view you can see the   
         group as the part of a menu contained between two lines. The parent of a group   
         must be a menu. -->  
    <Groups>  

      <!-- The main group is parented to the edit menu. All the buttons within the group  
           have the "CommandWellOnly" flag, so they're actually invisible, but it means  
           they get canonical names that begin with "Edit". Using placements, the group  
           is also placed in the GuidesSubMenu group. -->  
      <!-- The priority 0xB801 is chosen so it goes just after   
           IDG_VS_EDIT_COMMANDWELL -->  
      <Group guid="guidColumnGuidesCommandSet" id="GuidesMenuItemsGroup"  
             priority="0xB801">  
        <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_EDIT" />  
      </Group>  

      <!-- Group for holding the "Guidelines" sub-menu anchor (the item on the menu that  
           drops the sub menu). The group is parented to  
           the context menu for code windows. That takes care of most editors, but it's  
           also placed in a couple of other windows using Placements -->  
      <Group guid="guidColumnGuidesCommandSet" id="GuidesContextMenuGroup"   
             priority="0x0600">  
        <Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN" />  
      </Group>  

    </Groups>  

    <Menus>  
      <Menu guid="guidColumnGuidesCommandSet" id="GuidesSubMenu" priority="0x1000"  
            type="Menu">  
        <Parent guid="guidColumnGuidesCommandSet" id="GuidesContextMenuGroup" />  
        <Strings>  
          <ButtonText>&Column Guides</ButtonText>  
        </Strings>  
      </Menu>  
    </Menus>  

    <!--Buttons section. -->  
    <!--This section defines the elements the user can interact with, like a menu command or a button   
        or combo box in a toolbar. -->  
    <Buttons>  
      <!--To define a menu group you have to specify its ID, the parent menu and its   
          display priority.   
          The command is visible and enabled by default. If you need to change the   
          visibility, status, etc, you can use the CommandFlag node.  
          You can add more than one CommandFlag node e.g.:  
              <CommandFlag>DefaultInvisible</CommandFlag>  
              <CommandFlag>DynamicVisibility</CommandFlag>  
          If you do not want an image next to your command, remove the Icon node or   
          set it to <Icon guid="guidOfficeIcon" id="msotcidNoIcon" /> -->  

      <Button guid="guidColumnGuidesCommandSet" id="cmdidAddColumnGuide"   
              priority="0x0100" type="Button">  
        <Parent guid="guidColumnGuidesCommandSet" id="GuidesMenuItemsGroup" />  
        <Icon guid="guidImages" id="bmpPicAddGuide" />  
        <CommandFlag>CommandWellOnly</CommandFlag>  
        <CommandFlag>AllowParams</CommandFlag>  
        <Strings>  
          <ButtonText>&Add Column Guide</ButtonText>  
        </Strings>  
      </Button>  

      <Button guid="guidColumnGuidesCommandSet" id="cmdidRemoveColumnGuide"   
              priority="0x0101" type="Button">  
        <Parent guid="guidColumnGuidesCommandSet" id="GuidesMenuItemsGroup" />  
        <Icon guid="guidImages" id="bmpPicRemoveGuide" />  
        <CommandFlag>CommandWellOnly</CommandFlag>  
        <CommandFlag>AllowParams</CommandFlag>  
        <Strings>  
          <ButtonText>&Remove Column Guide</ButtonText>  
        </Strings>  
      </Button>  

      <Button guid="guidColumnGuidesCommandSet" id="cmdidChooseGuideColor"   
              priority="0x0103" type="Button">  
        <Parent guid="guidColumnGuidesCommandSet" id="GuidesMenuItemsGroup" />  
        <Icon guid="guidImages" id="bmpPicChooseColor" />  
        <CommandFlag>CommandWellOnly</CommandFlag>  
        <Strings>  
          <ButtonText>Column Guide &Color...</ButtonText>  
        </Strings>  
      </Button>  

      <Button guid="guidColumnGuidesCommandSet" id="cmdidRemoveAllColumnGuides"   
              priority="0x0102" type="Button">  
        <Parent guid="guidColumnGuidesCommandSet" id="GuidesMenuItemsGroup" />  
        <CommandFlag>CommandWellOnly</CommandFlag>  
        <Strings>  
          <ButtonText>Remove A&ll Columns</ButtonText>  
        </Strings>  
      </Button>  
    </Buttons>  

    <!--The bitmaps section is used to define the bitmaps that are used for the  
        commands.-->  
    <Bitmaps>  
      <!--  The bitmap id is defined in a way that is a little bit different from the  
            others:   
            the declaration starts with a guid for the bitmap strip, then there is the  
            resource id of the bitmap strip containing the bitmaps and then there are   
            the numeric ids of the elements used inside a button definition. An important  
            aspect of this declaration is that the element id   
            must be the actual index (1-based) of the bitmap inside the bitmap strip. -->  
      <Bitmap guid="guidImages" href="Resources\ColumnGuideCommands.png"   
              usedList="bmpPicAddGuide, bmpPicRemoveGuide, bmpPicChooseColor" />  
    </Bitmaps>  

  </Commands>  

  <CommandPlacements>  

    <!-- Define secondary placements for our groups -->  

    <!-- Place the group containing the three commands in the sub-menu -->  
    <CommandPlacement guid="guidColumnGuidesCommandSet" id="GuidesMenuItemsGroup"   
                      priority="0x0100">  
      <Parent guid="guidColumnGuidesCommandSet" id="GuidesSubMenu" />  
    </CommandPlacement>  

    <!-- The HTML editor context menu, for some reason, redefines its own groups  
         so we need to place a copy of our context menu there too. -->  
    <CommandPlacement guid="guidColumnGuidesCommandSet" id="GuidesContextMenuGroup"   
                      priority="0x1001">  
      <Parent guid="CMDSETID_HtmEdGrp" id="IDMX_HTM_SOURCE_HTML" />  
    </CommandPlacement>  

    <!-- The HTML context menu in Dev12 changed. -->  
    <CommandPlacement guid="guidColumnGuidesCommandSet" id="GuidesContextMenuGroup"   
                      priority="0x1001">  
      <Parent guid="CMDSETID_HtmEdGrp_Dev12" id="IDMX_HTM_SOURCE_HTML_Dev12" />  
    </CommandPlacement>  

    <!-- Similarly for Script -->  
    <CommandPlacement guid="guidColumnGuidesCommandSet" id="GuidesContextMenuGroup"  
                      priority="0x1001">  
      <Parent guid="CMDSETID_HtmEdGrp" id="IDMX_HTM_SOURCE_SCRIPT" />  
    </CommandPlacement>  

    <!-- Similarly for ASPX  -->  
    <CommandPlacement guid="guidColumnGuidesCommandSet" id="GuidesContextMenuGroup"   
                      priority="0x1001">  
      <Parent guid="CMDSETID_HtmEdGrp" id="IDMX_HTM_SOURCE_ASPX" />  
    </CommandPlacement>  

    <!-- Similarly for the XAML editor context menu -->  
    <CommandPlacement guid="guidColumnGuidesCommandSet" id="GuidesContextMenuGroup"  
                      priority="0x0600">  
      <Parent guid="guidXamlUiCmds" id="IDM_XAML_EDITOR" />  
    </CommandPlacement>  

  </CommandPlacements>  

  <!-- This defines the identifiers and their values used above to index resources  
       and specify commands. -->  
  <Symbols>  
    <!-- This is the package guid. -->  
    <GuidSymbol name="guidColumnGuideCommandsPkg"   
                value="{e914e5de-0851-4904-b361-1a3a9d449704}" />  

    <!-- This is the guid used to group the menu commands together -->  
    <GuidSymbol name="guidColumnGuidesCommandSet"   
                value="{c2bc0047-8bfa-4e5a-b5dc-45af8c274d8e}">  
      <IDSymbol name="GuidesContextMenuGroup" value="0x1020" />  
      <IDSymbol name="GuidesMenuItemsGroup" value="0x1021" />  
      <IDSymbol name="GuidesSubMenu" value="0x1022" />  
      <IDSymbol name="cmdidAddColumnGuide" value="0x0100" />  
      <IDSymbol name="cmdidRemoveColumnGuide" value="0x0101" />  
      <IDSymbol name="cmdidChooseGuideColor" value="0x0102" />  
      <IDSymbol name="cmdidRemoveAllColumnGuides" value="0x0103" />  
    </GuidSymbol>  

    <GuidSymbol name="guidImages" value="{2C99F852-587C-43AF-AA2D-F605DE2E46EF}">  
      <IDSymbol name="bmpPicAddGuide" value="1" />  
      <IDSymbol name="bmpPicRemoveGuide" value="2" />  
      <IDSymbol name="bmpPicChooseColor" value="3" />  
    </GuidSymbol>  

    <GuidSymbol name="CMDSETID_HtmEdGrp_Dev12"   
                value="{78F03954-2FB8-4087-8CE7-59D71710B3BB}">  
      <IDSymbol name="IDMX_HTM_SOURCE_HTML_Dev12" value="0x1" />  
    </GuidSymbol>  

    <GuidSymbol name="CMDSETID_HtmEdGrp" value="{d7e8c5e1-bdb8-11d0-9c88-0000f8040a53}">  
      <IDSymbol name="IDMX_HTM_SOURCE_HTML" value="0x33" />  
      <IDSymbol name="IDMX_HTM_SOURCE_SCRIPT" value="0x34" />  
      <IDSymbol name="IDMX_HTM_SOURCE_ASPX" value="0x35" />  
    </GuidSymbol>  

    <GuidSymbol name="guidXamlUiCmds" value="{4c87b692-1202-46aa-b64c-ef01faec53da}">  
      <IDSymbol name="IDM_XAML_EDITOR" value="0x103" />  
    </GuidSymbol>  
  </Symbols>  

</CommandTable>  

GUID.GUIDS. Pour Visual Studio rechercher vos gestionnaires de commandes et de les appeler, vous devez vérifier le package GUID déclaré dans le ColumnGuideCommandsPackage.cs (générée à partir du modèle d’élément de projet) correspond à celui du package GUID déclaré dans le .vsct fichier (copié à partir du haut).For Visual Studio to find your command handlers and invoke them, you need to ensure the package GUID declared in the ColumnGuideCommandsPackage.cs file (generated from the project item template) matches the package GUID declared in the .vsct file (copied from above). Si vous réutilisez cet exemple de code, il se peut que vous devez vous assurer de qu'avoir un GUID différent afin que vous ne sont pas en conflit avec une autre personne pouvez avoir copié ce code.If you re-use this sample code, you should make sure you have a different GUID so that you do not conflict with anyone else who may have copied this code.

Recherchez la ligne suivante dans ColumnGuideCommandsPackage.cs et copiez le GUID entre guillemets :Find this line in ColumnGuideCommandsPackage.cs and copy the GUID from between the quotation marks:

public const string PackageGuidString = "ef726849-5447-4f73-8de5-01b9e930f7cd";  

Ensuite, collez le GUID dans le .vsct de fichiers afin que vous avez la ligne suivante dans votre Symbols déclarations :Then, paste the GUID in the .vsct file so that you have the following line in your Symbols declarations:

<GuidSymbol name="guidColumnGuideCommandsPkg"   
            value="{ef726849-5447-4f73-8de5-01b9e930f7cd}" />  

Définir les GUID de la commande et le fichier d’image bitmap doit être unique pour vos extensions, trop :The GUIDs for the command set and the bitmap image file should be unique for your extensions, too:

<GuidSymbol name="guidColumnGuidesCommandSet"   
            value="{c2bc0047-8bfa-4e5a-b5dc-45af8c274d8e}">  
<GuidSymbol name="guidImages" value="{2C99F852-587C-43AF-AA2D-F605DE2E46EF}">  

Toutefois, vous n’avez pas besoin de modifier le jeu de commandes et bitmap GUID d’image dans cette procédure pas à pas pour obtenir le code fonctionne.But, you do not need to change the command set and bitmap image GUIDs in this walkthrough to get the code to work. Le jeu de commandes GUID doit correspondre à la déclaration dans le ColumnGuideCommands.cs fichier, mais vous remplacez le contenu de ce fichier, trop ; par conséquent, les GUID correspondra.The command set GUID needs to match the declaration in the ColumnGuideCommands.cs file, but you replace the contents of that file, too; therefore, the GUIDs will match.

Autres GUID dans le .vsct fichier identifier menus préexistants à laquelle les commandes de guide de colonne sont ajoutés, afin qu’ils ne changent jamais.Other GUIDs in the .vsct file identify pre-existing menus to which the column guide commands are added, so they never change.

Sections du fichier.File sections. Le .vsct comporte trois sections externes : commandes, des emplacements et des symboles.The .vsct has three outer sections: commands, placements, and symbols. La section commands définit les groupes de commandes, des menus, des boutons ou des éléments de menu et des bitmaps pour les icônes.The commands section defines command groups, menus, buttons or menu items, and bitmaps for icons. La section placements déclare où allument de groupes dans les menus ou des emplacements supplémentaires sur les menus préexistants.The placements section declares where groups go on menus or additional placements onto pre-existing menus. La section symbols déclare les identificateurs utilisés ailleurs dans le .vsct fichier, ce qui rend le .vsct code plus lisible que d’avoir des GUID et hex nombres partout.The symbols section declares identifiers used elsewhere in the .vsct file, which makes the .vsct code more readable than having GUIDs and hex numbers everywhere.

Section des commandes, de groupes de définitions.Commands section, groups definitions. La section commands définit tout d’abord les groupes de commandes.The commands section first defines command groups. Groupes de commandes sont des commandes qui se qu'affichent dans les menus avec les lignes grises légères en séparant les groupes.Groups of commands are commands you see in menus with slight gray lines separating the groups. Un groupe peut également remplir un sous-menu entière, comme dans cet exemple, et vous ne voyez pas la couleur grise en séparant les lignes dans ce cas.A group may also fill an entire sub menu, as in this example, and you do not see the gray separating lines in this case. Le .vsct fichiers déclarent deux groupes, les GuidesMenuItemsGroup qui est apparenté à la IDM_VS_MENU_EDIT (principal modifier menu) et le GuidesContextMenuGroup qui est apparenté à la IDM_VS_CTXT_CODEWIN (le code menu contextuel de l’éditeur).The .vsct files declare two groups, the GuidesMenuItemsGroup that is parented to the IDM_VS_MENU_EDIT (the main Edit menu) and the GuidesContextMenuGroup that is parented to the IDM_VS_CTXT_CODEWIN (the code editor's context menu).

La seconde déclaration de groupe a un 0x0600 priorité :The second group declaration has a 0x0600 priority:

<Group guid="guidColumnGuidesCommandSet" id="GuidesContextMenuGroup"   
             priority="0x0600">  

L’idée est de placer la colonne guides de sous-menu à la fin d’un menu contextuel quelconque auquel vous ajoutez le groupe de menus sub.The idea is to put the column guides sub menu at the end of any context menu to which you add the sub menu group. Mais, vous ne devez pas supposer vous sont familiers et forcez le sous-menu doit toujours être la dernière à l’aide d’une priorité de 0xFFFF.But, you shouldn't assume you know best and force the sub menu to always be last by using a priority of 0xFFFF. Vous devez faire des essais avec le nombre pour voir où votre sous-menu repose sur les menus contextuels de l’endroit où vous le placez.You have to experiment with the number to see where your sub menu lies on the context menus where you place it. Dans ce cas, 0x0600 est suffisamment élevé pour le placer à la fin des menus autant que vous pouvez le voir, mais elle laisse de la place pour quelqu'un d’autre pour concevoir leur extension soit inférieur à l’extension de repères de colonne si c’est souhaitable.In this case, 0x0600 is high enough to put it at the end of the menus as far as you can see, but it leaves room for someone else to design their extension to be lower than the column guides extension if that's desirable.

Section, définition du menu commandes.Commands section, menu definition. Ensuite, la section de la commande définit le sous-menu GuidesSubMenuapparenté à la GuidesContextMenuGroup.Next, the command section defines the sub menu GuidesSubMenu, parented to the GuidesContextMenuGroup. Le GuidesContextMenuGroup est le groupe que vous ajoutez à tous les menus de contexte pertinent.The GuidesContextMenuGroup is the group you add to all the relevant context menus. Dans la section emplacements, le code place le groupe avec les commandes de guide de quatre colonnes sur ce sous-menu.In the placements section, the code places the group with the four-column guide commands on this sub menu.

Section des commandes, boutons définitions.Commands section, buttons definitions. La section commands définit ensuite les éléments de menu ou les boutons qui sont les commandes de guides de quatre colonnes.The commands section then defines the menu items or buttons that are the four-column guides commands. CommandWellOnly, décrits ci-dessus, signifie que les commandes sont invisibles lorsqu’elle est placée dans un menu principal.CommandWellOnly, discussed above, means the commands are invisible when placed on a main menu. Deux de l’élément de menu bouton déclarations (guide d’ajouter et supprimer des guide) ont également un AllowParams indicateur :Two of the menu item button declarations (add guide and remove guide) also have an AllowParams flag:

<CommandFlag>AllowParams</CommandFlag>  

Cet indicateur active, ainsi que d’avoir des placements de menu principal, la commande pour recevoir des arguments lorsque Visual Studio appelle le Gestionnaire de commandes.This flag enables, along with having main menu placements, the command to receive arguments when Visual Studio invokes the command handler. Si l’utilisateur exécute la commande à partir de la fenêtre de commande, l’argument est passé au Gestionnaire de commandes de l’événement est arguments.If the user runs the command from the Command Window, the argument is passed to the command handler in the event arguments.

Sections de commande, les définitions de bitmaps.Command sections, bitmaps definitions. Enfin, la section commands déclare les fichiers bitmap ou des icônes utilisées pour les commandes.Lastly, the commands section declares the bitmaps or icons used for the commands. Cette section est une déclaration simple qui identifie la ressource de projet et répertorie les index sur une des icônes utilisées.This section is a simple declaration that identifies the project resource and lists one-based indexes of used icons. La section symbols de la .vsct fichier déclare les valeurs des identificateurs utilisés en tant qu’index.The symbols section of the .vsct file declares the values of the identifiers used as indexes. Cette procédure pas à pas utilise la bande de bitmaps fournie avec le modèle d’élément de commande personnalisé ajouté au projet.This walkthrough uses the bitmap strip provided with the custom command item template added to the project.

Section de placements.Placements section. Après les commandes section est la section de placement.After the commands section is the placements section. Le premier est où le code ajoute le premier groupe abordé ci-dessus qui conserve le guide de quatre colonnes commandes pour le sous-menu dans lequel les commandes s’affichent :The first one is where the code adds the first group discussed above that holds the four-column guide commands to the sub menu where the commands appear:

<CommandPlacement guid="guidColumnGuidesCommandSet" id="GuidesMenuItemsGroup"   
                  priority="0x0100">  
  <Parent guid="guidColumnGuidesCommandSet" id="GuidesSubMenu" />  
</CommandPlacement>  

Tous les autres positionnements ajouter le GuidesContextMenuGroup (qui contient le GuidesSubMenu) pour les autres menus contextuels de l’éditeur.All of the other placements add the GuidesContextMenuGroup (which contains the GuidesSubMenu) to other editor context menus. Lorsque le code déclaré le GuidesContextMenuGroup, il a été apparenté au menu contextuel de l’éditeur de code.When the code declared the GuidesContextMenuGroup, it was parented to the code editor's context menu. C’est pourquoi vous ne voyez pas d’emplacement pour le menu contextuel de l’éditeur de code.That's why you don't see a placement for the code editor's context menu.

Symboles de section.Symbols section. Comme indiqué ci-dessus, la section symbols déclare les identificateurs utilisés ailleurs dans le .vsct fichier, ce qui rend le .vsct code plus lisible que d’avoir des GUID et hex nombres partout.As stated above, the symbols section declares identifiers used elsewhere in the .vsct file, which makes the .vsct code more readable than having GUIDs and hex numbers everywhere. Les points importants de cette section sont que le GUID du package doit correspondre à la déclaration de la classe de package.The important points in this section are that the package GUID must agree with the declaration in the package class. Et, le GUID du jeu de commandes doit correspondre à la déclaration de la classe d’implémentation de commande.And, the command set GUID must agree with the declaration in the command implementation class.

Implémenter les commandesImplement the commands

Le ColumnGuideCommands.cs fichier implémente les commandes et raccorde les gestionnaires.The ColumnGuideCommands.cs file implements the commands and hooks up the handlers. Lorsque Visual Studio charge le package et l’initialise, le package est à son tour appelle Initialize sur la classe d’implémentation de commandes.When Visual Studio loads the package and initializes it, the package in turn calls Initialize on the commands implementation class. L’initialisation de commandes instancie simplement la classe, et le constructeur se raccorde les gestionnaires de commandes.The commands initialization simply instantiates the class, and the constructor hooks up all the command handlers.

Remplacez le contenu de la ColumnGuideCommands.cs fichier par le code suivant (voir ci-après) :Replace the contents of the ColumnGuideCommands.cs file with the following code (explained below):

using System;  
using System.ComponentModel.Design;  
using System.Globalization;  
using Microsoft.VisualStudio.Shell;  
using Microsoft.VisualStudio.Shell.Interop;  
using Microsoft.VisualStudio.TextManager.Interop;  
using Microsoft.VisualStudio.Text.Editor;  
using Microsoft.VisualStudio;  

namespace ColumnGuides  
{  
    /// <summary>  
    /// Command handler  
    /// </summary>  
    internal sealed class ColumnGuideCommands  
    {  

        const int cmdidAddColumnGuide = 0x0100;  
        const int cmdidRemoveColumnGuide = 0x0101;  
        const int cmdidChooseGuideColor = 0x0102;  
        const int cmdidRemoveAllColumnGuides = 0x0103;  

        /// <summary>  
        /// Command menu group (command set GUID).  
        /// </summary>  
        static readonly Guid CommandSet =   
            new Guid("c2bc0047-8bfa-4e5a-b5dc-45af8c274d8e");  

        /// <summary>  
        /// VS Package that provides this command, not null.  
        /// </summary>  
        private readonly Package package;  

        OleMenuCommand _addGuidelineCommand;  
        OleMenuCommand _removeGuidelineCommand;  

        /// <summary>  
        /// Initializes the singleton instance of the command.  
        /// </summary>  
        /// <param name="package">Owner package, not null.</param>  
        public static void Initialize(Package package)  
        {  
            Instance = new ColumnGuideCommands(package);  
        }  

        /// <summary>  
        /// Gets the instance of the command.  
        /// </summary>  
        public static ColumnGuideCommands Instance  
        {  
            get;  
            private set;  
        }  

        /// <summary>  
        /// Initializes a new instance of the <see cref="ColumnGuideCommands"/> class.  
        /// Adds our command handlers for menu (commands must exist in the command   
        /// table file)  
        /// </summary>  
        /// <param name="package">Owner package, not null.</param>  
        private ColumnGuideCommands(Package package)  
        {  
            if (package == null)  
            {  
                throw new ArgumentNullException("package");  
            }  

            this.package = package;  

            // Add our command handlers for menu (commands must exist in the .vsct file)  

            OleMenuCommandService commandService =  
                this.ServiceProvider.GetService(typeof(IMenuCommandService))  
                    as OleMenuCommandService;  
            if (commandService != null)  
            {  
                // Add guide  
                _addGuidelineCommand =   
                    new OleMenuCommand(AddColumnGuideExecuted, null,  
                                       AddColumnGuideBeforeQueryStatus,  
                                       new CommandID(ColumnGuideCommands.CommandSet,  
                                                     cmdidAddColumnGuide));  
                _addGuidelineCommand.ParametersDescription = "<column>";  
                commandService.AddCommand(_addGuidelineCommand);  
                // Remove guide  
                _removeGuidelineCommand =  
                    new OleMenuCommand(RemoveColumnGuideExecuted, null,  
                                       RemoveColumnGuideBeforeQueryStatus,  
                                       new CommandID(ColumnGuideCommands.CommandSet,  
                                                     cmdidRemoveColumnGuide));  
                _removeGuidelineCommand.ParametersDescription = "<column>";  
                commandService.AddCommand(_removeGuidelineCommand);  
                // Choose color  
                commandService.AddCommand(  
                    new MenuCommand(ChooseGuideColorExecuted,  
                                    new CommandID(ColumnGuideCommands.CommandSet,  
                                                  cmdidChooseGuideColor)));  
                // Remove all  
                commandService.AddCommand(  
                    new MenuCommand(RemoveAllGuidelinesExecuted,  
                                    new CommandID(ColumnGuideCommands.CommandSet,  
                                                  cmdidRemoveAllColumnGuides)));  
            }  
        }  

        /// <summary>  
        /// Gets the service provider from the owner package.  
        /// </summary>  
        private IServiceProvider ServiceProvider  
        {  
            get  
            {  
                return this.package;  
            }  
        }  

        private void AddColumnGuideBeforeQueryStatus(object sender, EventArgs e)  
        {  
            int currentColumn = GetCurrentEditorColumn();  
            _addGuidelineCommand.Enabled =  
                GuidesSettingsManager.CanAddGuideline(currentColumn);  
        }  

        private void RemoveColumnGuideBeforeQueryStatus(object sender, EventArgs e)  
        {  
            int currentColumn = GetCurrentEditorColumn();  
            _removeGuidelineCommand.Enabled =  
                GuidesSettingsManager.CanRemoveGuideline(currentColumn);  
        }  

        private int GetCurrentEditorColumn()  
        {  
            IVsTextView view = GetActiveTextView();  
            if (view == null)  
            {  
                return -1;  
            }  

            try  
            {  
                IWpfTextView textView = GetTextViewFromVsTextView(view);  
                int column = GetCaretColumn(textView);  

                // Note: GetCaretColumn returns 0-based positions. Guidelines are 1-based  
                // positions.  
                // However, do not subtract one here since the caret is positioned to the  
                // left of  
                // the given column and the guidelines are positioned to the right. We  
                // want the  
                // guideline to line up with the current caret position. e.g. When the  
                // caret is  
                // at position 1 (zero-based), the status bar says column 2. We want to  
                // add a  
                // guideline for column 1 since that will place the guideline where the  
                // caret is.  
                return column;  
            }  
            catch (InvalidOperationException)  
            {  
                return -1;  
            }  
        }  

        /// <summary>  
        /// Find the active text view (if any) in the active document.  
        /// </summary>  
        /// <returns>The IVsTextView of the active view, or null if there is no active  
        /// document or the  
        /// active view in the active document is not a text view.</returns>  
        private IVsTextView GetActiveTextView()  
        {  
            IVsMonitorSelection selection =  
                this.ServiceProvider.GetService(typeof(IVsMonitorSelection))  
                                                    as IVsMonitorSelection;  
            object frameObj = null;  
            ErrorHandler.ThrowOnFailure(  
                selection.GetCurrentElementValue(  
                    (uint)VSConstants.VSSELELEMID.SEID_DocumentFrame, out frameObj));  

            IVsWindowFrame frame = frameObj as IVsWindowFrame;  
            if (frame == null)  
            {  
                return null;  
            }  

            return GetActiveView(frame);  
        }  

        private static IVsTextView GetActiveView(IVsWindowFrame windowFrame)  
        {  
            if (windowFrame == null)  
            {  
                throw new ArgumentException("windowFrame");  
            }  

            object pvar;  
            ErrorHandler.ThrowOnFailure(  
                windowFrame.GetProperty((int)__VSFPROPID.VSFPROPID_DocView, out pvar));  

            IVsTextView textView = pvar as IVsTextView;  
            if (textView == null)  
            {  
                IVsCodeWindow codeWin = pvar as IVsCodeWindow;  
                if (codeWin != null)  
                {  
                    ErrorHandler.ThrowOnFailure(codeWin.GetLastActiveView(out textView));  
                }  
            }  
            return textView;  
        }  

        private static IWpfTextView GetTextViewFromVsTextView(IVsTextView view)  
        {  

            if (view == null)  
            {  
                throw new ArgumentNullException("view");  
            }  

            IVsUserData userData = view as IVsUserData;  
            if (userData == null)  
            {  
                throw new InvalidOperationException();  
            }  

            object objTextViewHost;  
            if (VSConstants.S_OK  
                   != userData.GetData(Microsoft.VisualStudio  
                                                .Editor  
                                                .DefGuidList.guidIWpfTextViewHost,  
                                       out objTextViewHost))  
            {  
                throw new InvalidOperationException();  
            }  

            IWpfTextViewHost textViewHost = objTextViewHost as IWpfTextViewHost;  
            if (textViewHost == null)  
            {  
                throw new InvalidOperationException();  
            }  

            return textViewHost.TextView;  
        }  

        /// <summary>  
        /// Given an IWpfTextView, find the position of the caret and report its column  
        /// number. The column number is 0-based  
        /// </summary>  
        /// <param name="textView">The text view containing the caret</param>  
        /// <returns>The column number of the caret's position. When the caret is at the  
        /// leftmost column, the return value is zero.</returns>  
        private static int GetCaretColumn(IWpfTextView textView)  
        {  
            // This is the code the editor uses to populate the status bar.  
            Microsoft.VisualStudio.Text.Formatting.ITextViewLine caretViewLine =  
                textView.Caret.ContainingTextViewLine;  
            double columnWidth = textView.FormattedLineSource.ColumnWidth;  
            return (int)(Math.Round((textView.Caret.Left - caretViewLine.Left)  
                                       / columnWidth));  
        }  

        /// <summary>  
        /// Determine the applicable column number for an add or remove command.  
        /// The column is parsed from command arguments, if present. Otherwise  
        /// the current position of the caret is used to determine the column.  
        /// </summary>  
        /// <param name="e">Event args passed to the command handler.</param>  
        /// <returns>The column number. May be negative to indicate the column number is  
        /// unavailable.</returns>  
        /// <exception cref="ArgumentException">The column number parsed from event args  
        /// was not a valid integer.</exception>  
        private int GetApplicableColumn(EventArgs e)  
        {  
            var inValue = ((OleMenuCmdEventArgs)e).InValue as string;  
            if (!string.IsNullOrEmpty(inValue))  
            {  
                int column;  
                if (!int.TryParse(inValue, out column) || column < 0)  
                    throw new ArgumentException("Invalid column");  
                return column;  
            }  

            return GetCurrentEditorColumn();  
        }  

        /// <summary>  
        /// This function is the callback used to execute a command when the a menu item  
        /// is clicked. See the Initialize method to see how the menu item is associated  
        /// to this function using the OleMenuCommandService service and the MenuCommand  
        /// class.  
        /// </summary>  
        private void AddColumnGuideExecuted(object sender, EventArgs e)  
        {  
            int column = GetApplicableColumn(e);  
            if (column >= 0)  
            {  
                GuidesSettingsManager.AddGuideline(column);  
            }  
        }  

        private void RemoveColumnGuideExecuted(object sender, EventArgs e)  
        {  
            int column = GetApplicableColumn(e);  
            if (column >= 0)  
            {  
                GuidesSettingsManager.RemoveGuideline(column);  
            }  
        }  

        private void RemoveAllGuidelinesExecuted(object sender, EventArgs e)  
        {  
            GuidesSettingsManager.RemoveAllGuidelines();  
        }  

        private void ChooseGuideColorExecuted(object sender, EventArgs e)  
        {  
            System.Windows.Media.Color color = GuidesSettingsManager.GuidelinesColor;  

            using (System.Windows.Forms.ColorDialog picker =   
                new System.Windows.Forms.ColorDialog())  
            {  
                picker.Color = System.Drawing.Color.FromArgb(255, color.R, color.G,  
                                                             color.B);  
                if (picker.ShowDialog() == System.Windows.Forms.DialogResult.OK)  
                {  
                    GuidesSettingsManager.GuidelinesColor =   
                        System.Windows.Media.Color.FromRgb(picker.Color.R,  
                                                           picker.Color.G,   
                                                           picker.Color.B);  
                }  
            }  
        }  

    }  
}  

Corriger les références.Fix references. Il vous manque une référence à ce stade.You're missing a reference at this point. Appuyez sur le bouton droit du pointeur sur le nœud Références dans l’Explorateur de solutions.Press the right pointer button on the References node in the Solution Explorer. Choisissez le ajouter... commande.Choose the Add ... command. Le ajouter une référence boîte de dialogue comporte une zone de recherche dans le coin supérieur droit.The Add Reference dialog has a search box in the upper-right corner. Entrez « éditeur » (sans les guillemets doubles).Enter "editor" (without the double quotes). Choisissez le Microsoft.VisualStudio.Editor élément (vous devez cocher la case à gauche de l’élément, sélectionnez simplement l’élément) et choisissez OK pour ajouter la référence.Choose the Microsoft.VisualStudio.Editor item (you must check the box to the left of the item, not just select the item) and choose OK to add the reference.

L’initialisation.Initialization. Lors de l’initialisation de la classe de package, il appelle Initialize sur la classe d’implémentation de commandes.When the package class initializes, it calls Initialize on the commands implementation class. Le ColumnGuideCommands instancie la classe de l’initialisation et enregistre l’instance de classe et de la référence de package dans les membres de classe.The ColumnGuideCommands initialization instantiates the class and saves the class instance and the package reference in class members.

Nous allons examiner un des raccordement du Gestionnaire de commande des sauvegardes à partir du constructeur de classe :Let's look at one of the command handler hook-ups from the class constructor:

_addGuidelineCommand =   
    new OleMenuCommand(AddColumnGuideExecuted, null,  
                       AddColumnGuideBeforeQueryStatus,  
                       new CommandID(ColumnGuideCommands.CommandSet,  
                                     cmdidAddColumnGuide));  

Vous créez un OleMenuCommand.You create an OleMenuCommand. Visual Studio utilise le système de commande de Microsoft Office.Visual Studio uses the Microsoft Office command system. Les arguments clés lorsque vous instanciez un OleMenuCommand est la fonction qui implémente la commande (AddColumnGuideExecuted), la fonction à appeler lorsque Visual Studio affiche un menu avec la commande (AddColumnGuideBeforeQueryStatus) et l’ID de commande.The key arguments when instantiating an OleMenuCommand is the function that implements the command (AddColumnGuideExecuted), the function to call when Visual Studio shows a menu with the command (AddColumnGuideBeforeQueryStatus), and the command ID. Visual studio appelle la fonction d’état de requête avant d’afficher une commande dans un menu afin que la commande peut rendre invisible ou grisés pour un affichage du menu particulier (par exemple, la désactivation de copie s’il n’existe aucune sélection), modifier son icône, ou encore modifier son nom (par exemple, d’ajouter un élément à supprimer un élément) et ainsi de suite.Visual studio calls the query status function before showing a command on a menu so that the command can make itself invisible or greyed out for a particular display of the menu (for example, disabling Copy if there's no selection), change its icon, or even change its name (for example, from Add Something to Remove Something), and so on. L’ID de commande doit correspondre à une commande ID déclaré dans le .vsct fichier.The command ID must match a command ID declared in the .vsct file. Les chaînes pour le jeu de commandes et les repères de colonne Ajouter la commande doit correspondre entre la .vsct fichier et le ColumnGuideCommands.cs.The strings for the command set and the column guides add command must match between the .vsct file and the ColumnGuideCommands.cs.

La ligne suivante fournit une assistance pour les utilisateurs appeler la commande par le biais de la fenêtre de commande (voir ci-après) :The following line provides assistance for when users invoke the command via the Command Window (explained below):

_addGuidelineCommand.ParametersDescription = "<column>";  

État de la requête.Query status. Les fonctions d’état de requête AddColumnGuideBeforeQueryStatus et RemoveColumnGuideBeforeQueryStatus vérifier certains paramètres (tels que le nombre maximal de guides ou colonne max) ou s’il existe un repère de colonne à supprimer.The query status functions AddColumnGuideBeforeQueryStatus and RemoveColumnGuideBeforeQueryStatus check some settings (such as max number of guides or max column) or if there is a column guide to remove. Ils permettent les commandes si les conditions sont correctes.They enable the commands if the conditions are right. Fonctions d’état de requête doivent être efficaces, car elles s’exécutent chaque fois que Visual Studio affiche un menu et pour chaque commande sur le menu.Query status functions need to be efficient because they run every time Visual Studio shows a menu and for each command on the menu.

Fonction de AddColumnGuideExecuted.AddColumnGuideExecuted function. La partie intéressante de l’ajout d’un guide est de déterminer l’emplacement d’affichage et le signe insertion éditeur actuel.The interesting part of adding a guide is figuring out the current editor view and caret location. Tout d’abord, cette fonction appelle GetApplicableColumn, qui vérifie s’il existe un argument fourni par l’utilisateur dans les arguments d’événement du Gestionnaire de commandes, et si n’est pas, la fonction vérifie dans Affichage de l’éditeur :First, this function calls GetApplicableColumn, which checks if there is a user-supplied argument in the command handler's event arguments, and if there is none, the function checks the editor's view:

private int GetApplicableColumn(EventArgs e)  
{  
    var inValue = ((OleMenuCmdEventArgs)e).InValue as string;  
    if (!string.IsNullOrEmpty(inValue))  
    {  
        int column;  
        if (!int.TryParse(inValue, out column) || column < 0)  
            throw new ArgumentException("Invalid column");  
        return column;  
    }  

    return GetCurrentEditorColumn();  
}  

GetCurrentEditorColumn a aller un peu pour obtenir un IWpfTextView affichage du code.GetCurrentEditorColumn has to dig a little to get an IWpfTextView view of the code. Si vous tracez GetActiveTextView, GetActiveView, et GetTextViewFromVsTextView, vous pouvez voir comment procéder.If you trace through GetActiveTextView, GetActiveView, and GetTextViewFromVsTextView, you can see how to do that. Le code suivant est le code abstrait, en commençant par la sélection actuelle, obtention de frame de la sélection, puis bien DocView du bloc en tant qu’un IVsTextView, comment obtenir un IVsUserData à partir de la IVsTextView, puis l’obtention d’un hôte d’affichage, et enfin le IWpfTextView :The following code is the relevant code abstracted, starting with the current selection, then getting the selection's frame, then getting the frame's DocView as an IVsTextView, then getting an IVsUserData from the IVsTextView, then getting a view host, and finally the IWpfTextView:

   IVsMonitorSelection selection =  
       this.ServiceProvider.GetService(typeof(IVsMonitorSelection))   
           as IVsMonitorSelection;  
   object frameObj = null;  

ErrorHandler.ThrowOnFailure(selection.GetCurrentElementValue(  
                                (uint)VSConstants.VSSELELEMID.SEID_DocumentFrame,  
                                out frameObj));  

   IVsWindowFrame frame = frameObj as IVsWindowFrame;  
   if (frame == null)  
       <<do nothing>>;  

...  
   object pvar;  
   ErrorHandler.ThrowOnFailure(frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocView,  
                                                  out pvar));  

   IVsTextView textView = pvar as IVsTextView;  
   if (textView == null)  
   {  
       IVsCodeWindow codeWin = pvar as IVsCodeWindow;  
       if (codeWin != null)  
       {  
           ErrorHandler.ThrowOnFailure(codeWin.GetLastActiveView(out textView));  
       }  
   }  

...  
   if (textView == null)  
       <<do nothing>>  

   IVsUserData userData = textView as IVsUserData;  
   if (userData == null)  
       <<do nothing>>  

   object objTextViewHost;  
   if (VSConstants.S_OK   
           != userData.GetData(Microsoft.VisualStudio.Editor.DefGuidList  
                                                            .guidIWpfTextViewHost,  
                                out objTextViewHost))  
   {  
       <<do nothing>>  
   }  

   IWpfTextViewHost textViewHost = objTextViewHost as IWpfTextViewHost;  
   if (textViewHost == null)  
       <<do nothing>>  

   IWpfTextView textView = textViewHost.TextView;  

Une fois que vous avez une IWpfTextView, vous pouvez obtenir la colonne où se trouve le point d’insertion :Once you have an IWpfTextView, you can get the column where the caret is located:

private static int GetCaretColumn(IWpfTextView textView)  
{  
    // This is the code the editor uses to populate the status bar.  
    Microsoft.VisualStudio.Text.Formatting.ITextViewLine caretViewLine =  
        textView.Caret.ContainingTextViewLine;  
    double columnWidth = textView.FormattedLineSource.ColumnWidth;  
    return (int)(Math.Round((textView.Caret.Left - caretViewLine.Left)  
                                / columnWidth));  
}  

Avec la colonne actuelle dans la main lorsque l’utilisateur a cliqué, le code appelle simplement sur le Gestionnaire de paramètres pour ajouter ou supprimer la colonne.With the current column in hand where the user clicked, the code just calls on the settings manager to add or remove the column. Le Gestionnaire de paramètres déclenche l’événement auquel toutes ColumnGuideAdornment écoutent des objets.The settings manager fires the event to which all ColumnGuideAdornment objects listen. Lorsque l’événement se déclenche, ces objets mis à jour leurs points de vue de texte associée avec les nouveaux paramètres de guide de colonne.When the event fires, these objects update their associated text views with new column guide settings.

Appeler la commande à partir de la fenêtre de commandeInvoke command from the Command Window

L’exemple de repères de colonne permet aux utilisateurs d’appeler deux commandes à partir de la fenêtre de commande en tant que formulaire d’extensibilité.The column guides sample enables users to invoke two commands from the Command Window as a form of extensibility. Si vous utilisez le vue | Windows autres | fenêtre de commande commande, vous pouvez voir la fenêtre de commande.If you use the View | Other Windows | Command Window command, you can see the Command Window. Vous pouvez interagir avec la fenêtre de commande en entrant « modifier », et avec la saisie semi-automatique de nom de commande et en fournissant l’argument 120, vous avez le résultat suivant :You can interact with the Command Window by entering "edit.", and with command name completion and supplying the argument 120, you have the following result:

> Edit.AddColumnGuide 120  
>  

Les éléments de l’exemple qui permettent ce comportement sont dans le .vsct fichier déclarations, le ColumnGuideCommands constructeur de classe quand elle se raccorde les gestionnaires de commandes et les implémentations de gestionnaire de commandes qui vérifient les arguments d’événement.The pieces of the sample that enable this behavior are in the .vsct file declarations, the ColumnGuideCommands class constructor when it hooks up command handlers, and the command handler implementations that check event arguments.

Vous l’avez vu «<CommandFlag>CommandWellOnly</CommandFlag>» dans le .vsct de fichiers, ainsi que des placements dans le modifier menu principal même si les commandes ne sont pas affichés dans le modifier menu l’interface utilisateur.You saw "<CommandFlag>CommandWellOnly</CommandFlag>" in the .vsct file as well as placements in the Edit main menu even though the commands are not shown in the Edit menu UI. Leur présence sur les principaux modifier menu donne les noms tels que Edit.AddColumnGuide.Having them on the main Edit menu gives them names like Edit.AddColumnGuide. La déclaration de groupe de commandes qui contient les quatre commandes placé le groupe sur le modifier menu directement :The commands group declaration that holds the four commands placed the group on the Edit menu directly:

<Group guid="guidColumnGuidesCommandSet" id="GuidesMenuItemsGroup"  
             priority="0xB801">  
        <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_EDIT" />  
      </Group>  

La section boutons déclaré plus tard les commandes CommandWellOnly conserver invisible dans le menu principal et déclaré avec AllowParams:The buttons section later declared the commands CommandWellOnly to keep them invisible on the main menu and declared them with AllowParams:

<Button guid="guidColumnGuidesCommandSet" id="cmdidAddColumnGuide"   
        priority="0x0100" type="Button">  
  <Parent guid="guidColumnGuidesCommandSet" id="GuidesMenuItemsGroup" />  
  <Icon guid="guidImages" id="bmpPicAddGuide" />  
  <CommandFlag>CommandWellOnly</CommandFlag>  
  <CommandFlag>AllowParams</CommandFlag>  

Vous l’avez vu le Gestionnaire de commandes raccorder le code dans le ColumnGuideCommands constructeur de classe fourni une description du paramètre autorisé :You saw the command handler hook up code in the ColumnGuideCommands class constructor provided a description of the allowed parameter:

_addGuidelineCommand.ParametersDescription = "<column>";  

Vous avez vu le GetApplicableColumn fonction vérifications OleMenuCmdEventArgs pour une valeur avant de vérifier la vue de l’éditeur pour une colonne en cours :You saw the GetApplicableColumn function checks OleMenuCmdEventArgs for a value before checking the editor's view for a current column:

private int GetApplicableColumn(EventArgs e)  
{  
    var inValue = ((OleMenuCmdEventArgs)e).InValue as string;  
    if (!string.IsNullOrEmpty(inValue))  
    {  
        int column;  
        if (!int.TryParse(inValue, out column) || column < 0)  
            throw new ArgumentException("Invalid column");  
        return column;  
    }  

Essayez votre extensionTry your extension

Vous pouvez maintenant appuyer sur F5 pour exécuter votre extension de repères de colonne.You can now press F5 to execute your Column Guides extension. Ouvrez un fichier texte et utiliser le menu contextuel de l’éditeur pour ajouter des lignes de repère, supprimez-les et modifier leur couleur.Open a text file and use the editor's context menu to add guide lines, remove them, and change their color. Cliquez sur le texte (pas d’espace blanc dépassé la fin de la ligne) pour ajouter une colonne guide, ou l’éditeur ajoute à la dernière colonne sur la ligne.Click in the text (not whitespace passed the end of the line) to add a column guide, or the editor adds it to the last column on the line. Si vous utilisez la fenêtre de commande et appelez les commandes avec un argument, vous pouvez ajouter n’importe où les repères de colonne.If you use the Command Window and invoke the commands with an argument, you can add column guides anywhere.

Si vous voulez essayer de placements de commandes différents, de modifier les noms, de modifier les icônes et ainsi de suite, et que vous rencontrez des problèmes avec Visual Studio affiche le dernier code de menus, vous pouvez réinitialiser la ruche expérimentale, dans lequel vous effectuez un débogage.If you want to try different command placements, change names, change icons, and so on, and you have any problems with Visual Studio showing you the latest code in menus, you can reset the experimental hive in which you are debugging. Afficher le Menu Démarrer de Windows et tapez « réinitialiser ».Bring up the Windows Start Menu and type "reset". Recherchez et exécutez la commande, réinitialiser l’Instance expérimentale Visual Studio suivant.Look for and run the command, Reset the Next Visual Studio Experimental Instance. Cette commande nettoie la ruche expérimentale du Registre de tous les composants d’extension.This command cleans up the experimental registry hive of all extension components. Il n’existe pas nettoyer les paramètres à partir de composants, par conséquent, les guides vous aviez lorsque vous arrêtez la ruche expérimentale de Visual Studio ont toujours lieu lorsque votre code lit la banque de paramètres au lancement suivant.It does not clean out settings from components, so any guides you had when you shut down Visual Studio's experimental hive are still there when your code reads the settings store on next launch.

Projet de code terminéFinished code project

Il y aura bientôt d’un projet github d’exemples d’extensibilité de Visual Studio, et le projet achevé sera présent.There will soon be a github project of Visual Studio Extensibility samples, and the completed project will be there. Cet article sera être mis à jour pour pointer il lorsque cela se produit.This article will be updated to point there when that happens. Le projet d’exemple terminé peut-être avoir des GUID différents et aura une bande de bitmaps différentes pour les icônes de commande.The completed sample project may have different guids and will have a different bitmaps strip for the command icons.

Vous pouvez essayer une version de la fonctionnalité de repères de colonne avec cette galerie Visual Studioextension.You can try out a version of the column guides feature with this Visual Studio Galleryextension.

Voir aussiSee also

À l’intérieur de l’éditeur Inside the editor
Étendre les services de l’éditeur et la langue Extend the editor and language services
Points d’extension éditeur et le service de langage Language service and editor extension points
Étendre des menus et commandes Extend menus and commands
Ajouter un sous-menu à un menu Add a submenu to a menu
Créer une extension avec un éditeur de modèle d’élémentCreate an extension with an editor item template