Procédure pas à pas : affichage de suggestions AmpouleWalkthrough: Displaying Light Bulb Suggestions

Les ampoules sont les icônes utilisées dans l’éditeur Visual Studio et qui se développent pour afficher un ensemble d’actions, par exemple des correctifs pour les problèmes identifiés par les analyseurs de code intégrés ou la refactorisation de code.Light bulbs are icons used in the Visual Studio editor that expand to display a set of actions, for example fixes for problems identified by the built-in code analyzers or code refactoring.

Dans les éditeurs Visual c# et Visual Basic, vous pouvez également utiliser .NET Compiler Platform (« Roslyn ») pour écrire et empaqueter vos propres analyseurs de code avec des actions qui s’affiche automatiquement les ampoules.In the Visual C# and Visual Basic editors, you can also use the .NET Compiler Platform ("Roslyn") to write and package your own code analyzers with actions that display light bulbs automatically. Pour plus d'informations, voir :For more information, see:

  • Comment : Écrire un Diagnostic c# et la correction du CodeHow To: Write a C# Diagnostic and Code Fix

  • Comment : Écrire un Diagnostic de Visual Basic et de correction du CodeHow To: Write a Visual Basic Diagnostic and Code Fix

    Autres langages tels que C++ fournissent également des ampoules pour certaines actions rapides, comme une suggestion pour créer une implémentation de stub de cette fonction.Other languages such as C++ also provide light bulbs for some quick actions, such as a suggestion to create a stub implementation of that function.

    Voici à quoi ressemble une ampoule.Here's what a light bulb looks like. Dans un projet Visual Basic ou Visual c#, une ligne ondulée rouge s’affiche sous un nom de variable lorsqu’il n’est pas valide.In a Visual Basic or Visual C# project, a red squiggle appears under a variable name when it is invalid. Lorsque vous déplacez la souris sur l’identificateur non valide, une ampoule s’affiche près du curseur.When you mouse over the invalid identifier, a light bulb is displayed near the cursor.

    ampoulelight bulb

    Si vous cliquez sur la flèche orientée vers l’ampoule, un ensemble d’actions suggérées s’affiche, avec un aperçu de l’action sélectionnée.If you click the down arrow by the light bulb, a set of suggested actions is displayed, along with a preview of the selected action. Dans ce cas, il montre les modifications qui vont être apportées à votre code si vous exécutez l’action.In this case, it shows the changes that will be made to your code if you execute the action.

    aperçu d’ampoulelight bulb preview

    Vous pouvez utiliser des ampoules pour fournir vos propres actions suggérées.You can use light bulbs to provide your own suggested actions. Par exemple, vous pouvez fournir des actions pour déplacer l’ouverture des accolades pour une nouvelle ligne ou les déplacer à la fin de la ligne précédente.For example, you could provide actions to move opening curly braces to a new line or move them to the end of the preceding line. La procédure suivante montre comment créer une ampoule qui s’affiche sur le mot actuel et suggère deux actions : convertir en majuscules et convertir en minuscules.The following walkthrough shows how to create a light bulb that appears on the current word and has two suggested actions: Convert to upper case and Convert to lower case.

PrérequisPrerequisites

À 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 is 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 l’installation de Visual Studio SDK.For more information, see Installing the Visual Studio SDK.

Création d’un projet Managed Extensibility Framework (MEF)Creating a Managed Extensibility Framework (MEF) Project

  1. Créez un projet c# VSIX.Create a C# VSIX project. (Dans le nouveau projet boîte de dialogue, sélectionnez Visual c# / extensibilité, puis projet VSIX.) Nommez la solution LightBulbTest.(In the New Project dialog, select Visual C# / Extensibility, then VSIX Project.) Name the solution LightBulbTest.

  2. Ajouter un classifieur d’éditeur modèle d’élément au projet.Add an Editor Classifier item template to the project. Pour plus d’informations, consultez création d’une Extension avec un éditeur de modèle d’élément.For more information, see Creating an Extension with an Editor Item Template.

  3. Supprimez les fichiers de classe existants.Delete the existing class files.

  4. Ajoutez la référence suivante au projet et définissez copie locale à False:Add the following reference to the project, and set Copy Local to False:

    Microsoft.VisualStudio.Language.IntellisenseMicrosoft.VisualStudio.Language.Intellisense

  5. Ajoutez un nouveau fichier de classe et nommez-le LightBulbTest.Add a new class file and name it LightBulbTest.

  6. Ajoutez le code suivant à l’aide d’instructions :Add the following using statements:

    using System;  
    using System.Linq;  
    using System.Collections.Generic;  
    using System.Threading.Tasks;  
    using Microsoft.VisualStudio.Language.Intellisense;  
    using Microsoft.VisualStudio.Text;  
    using Microsoft.VisualStudio.Text.Editor;  
    using Microsoft.VisualStudio.Text.Operations;  
    using Microsoft.VisualStudio.Utilities;  
    using System.ComponentModel.Composition;  
    using System.Threading;  
    

Implémentation du fournisseur de Source d’ampouleImplementing the Light Bulb Source Provider

  1. Dans le fichier de classe LightBulbTest.cs, supprimez la classe LightBulbTest.In the LightBulbTest.cs class file, delete the LightBulbTest class. Ajoutez une classe nommée TestSuggestedActionsSourceProvider qui implémente ISuggestedActionsSourceProvider.Add a class named TestSuggestedActionsSourceProvider that implements ISuggestedActionsSourceProvider. Exporter avec un nom de Actions suggérées de Test et un ContentTypeAttribute de « texte ».Export it with a Name of Test Suggested Actions and a ContentTypeAttribute of "text".

    [Export(typeof(ISuggestedActionsSourceProvider))]  
    [Name("Test Suggested Actions")]  
    [ContentType("text")]  
    internal class TestSuggestedActionsSourceProvider : ISuggestedActionsSourceProvider  
    
  2. Dans la classe de fournisseur de source, importez le ITextStructureNavigatorSelectorService et l’ajouter en tant que propriété.Inside the source provider class, import the ITextStructureNavigatorSelectorService and add it as a property.

    [Import(typeof(ITextStructureNavigatorSelectorService))]  
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }  
    
  3. Implémentez le CreateSuggestedActionsSource méthode pour retourner un ISuggestedActionsSource objet.Implement the CreateSuggestedActionsSource method to return an ISuggestedActionsSource object. Nous aborderons la source dans la section suivante.We will discuss the source in the next section.

    public ISuggestedActionsSource CreateSuggestedActionsSource(ITextView textView, ITextBuffer textBuffer)  
    {  
        if (textBuffer == null || textView == null)  
        {  
            return null;  
        }  
        return new TestSuggestedActionsSource(this, textView, textBuffer);  
    }  
    

Implémentation de la ISuggestedActionSourceImplementing the ISuggestedActionSource

La source de l’action suggérée est responsable de la collecte de l’ensemble des actions suggérées et les ajouter dans le contexte approprié.The suggested action source is responsible for collecting the set of suggested actions and adding them in the right context. Dans ce cas le contexte est le mot actuel et les actions suggérées sont UpperCaseSuggestedAction et LowerCaseSuggestedAction, qui seront abordées dans la section suivante.In this case the context is the current word and the suggested actions are UpperCaseSuggestedAction and LowerCaseSuggestedAction, which we will discuss in the following section.

  1. Ajoutez une classe TestSuggestedActionsSource qui implémente ISuggestedActionsSource.Add a class TestSuggestedActionsSource that implements ISuggestedActionsSource.

    internal class TestSuggestedActionsSource : ISuggestedActionsSource  
    
  2. Ajouter des champs en lecture seule privés pour le fournisseur de code source action suggérée, la mémoire tampon de texte et l’affichage de texte.Add private read-only fields for the suggested action source provider, the text buffer and the text view.

    private readonly TestSuggestedActionsSourceProvider m_factory;  
    private readonly ITextBuffer m_textBuffer;  
    private readonly ITextView m_textView;  
    
  3. Ajoutez un constructeur qui définit les champs privés.Add a constructor that sets the private fields.

    public TestSuggestedActionsSource(TestSuggestedActionsSourceProvider testSuggestedActionsSourceProvider, ITextView textView, ITextBuffer textBuffer)  
    {  
        m_factory = testSuggestedActionsSourceProvider;  
        m_textBuffer = textBuffer;  
        m_textView = textView;  
    }  
    
  4. Ajoutez une méthode privée qui retourne le mot qui est actuellement sous le curseur.Add a private method that returns the word that is currently under the cursor. La méthode suivante ressemble à l’emplacement actuel du curseur et vous demande le navigateur de structure de texte pour l’étendue du mot.The following method looks at the current location of the cursor and asks the text structure navigator for the extent of the word. Si le curseur se trouve sur un mot, le TextExtent est retourné dans le paramètre out ; sinon la out paramètre est null et la méthode retourne false.If the cursor is on a word, the TextExtent is returned in the out parameter; otherwise the out parameter is null and the method returns false.

    private bool TryGetWordUnderCaret(out TextExtent wordExtent)  
    {  
        ITextCaret caret = m_textView.Caret;  
        SnapshotPoint point;  
    
        if (caret.Position.BufferPosition > 0)  
        {  
            point = caret.Position.BufferPosition - 1;  
        }  
        else  
        {  
            wordExtent = default(TextExtent);  
            return false;  
        }  
    
        ITextStructureNavigator navigator = m_factory.NavigatorService.GetTextStructureNavigator(m_textBuffer);  
    
        wordExtent = navigator.GetExtentOfWord(point);  
        return true;  
    }  
    
  5. Implémentez la méthode HasSuggestedActionsAsync.Implement the HasSuggestedActionsAsync method. L’éditeur appelle cette méthode pour déterminer s’il faut afficher l’ampoule.The editor calls this method to find out whether to display the light bulb. Cet appel est effectué, très souvent, par exemple, chaque fois que le curseur se déplace d’une ligne vers un autre, ou lorsque la souris pointe sur un soulignement ondulé d’erreur.This call is made quite often, for example whenever the cursor moves from one line to another, or when the mouse hovers over an error squiggle. Il est asynchrone afin d’autoriser d’autres opérations de l’interface utilisateur à effectuer pendant l’utilisation de cette méthode.It is asynchronous in order to allow other UI operations to carry on while this method is working. Dans la plupart des cas, que cette méthode doit effectuer certaines l’analyse et l’analyse de la ligne actuelle, par conséquent, le traitement peut prendre un certain temps.In most cases this method needs to perform some parsing and analysis of the current line, so the processing may take some time.

    Dans notre implémentation il obtient de manière asynchrone le TextExtent et détermine si l’étendue est significative, par exemple, il y a une autre qu’un espace blanc.In our implementation it asynchronously gets the TextExtent and determines whether the extent is significant, i.e., whether it has some text other than whitespace.

    public Task<bool> HasSuggestedActionsAsync(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken)  
    {  
        return Task.Factory.StartNew(() =>  
        {  
            TextExtent extent;  
            if (TryGetWordUnderCaret(out extent))  
            {  
                // don't display the action if the extent has whitespace  
                return extent.IsSignificant;  
              }  
            return false;  
        });  
    }  
    
  6. Implémentez le GetSuggestedActions (méthode), qui retourne un tableau de SuggestedActionSet objets qui contiennent les différentes ISuggestedAction objets.Implement the GetSuggestedActions method, which returns an array of SuggestedActionSet objects that contain the different ISuggestedAction objects. Cette méthode est appelée lorsque l’ampoule est développé.This method is called when the light bulb is expanded.

    Avertissement

    Vous devez vous assurer que les implémentations de HasSuggestedActionsAsync() et GetSuggestedActions() sont cohérent ; qui est, si HasSuggestedActionsAsync() retourne true, puis GetSuggestedActions() doit avoir certaines actions à afficher.You should make sure that the implementations of HasSuggestedActionsAsync() and GetSuggestedActions() are consistent; that is, if HasSuggestedActionsAsync() returns true, then GetSuggestedActions() should have some actions to display. Dans de nombreux cas HasSuggestedActionsAsync() est appelé juste avant GetSuggestedActions(), mais cela n’est pas toujours le cas.In many cases HasSuggestedActionsAsync() is called just before GetSuggestedActions(), but this is not always the case. Par exemple, si l’utilisateur appelle l’ampoule actions en appuyant sur (CTRL +.) uniquement GetSuggestedActions() est appelée.For example, if the user invokes the light bulb actions by pressing (CTRL + .) only GetSuggestedActions() is called.

    public IEnumerable<SuggestedActionSet> GetSuggestedActions(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken)  
    {  
        TextExtent extent;  
        if (TryGetWordUnderCaret(out extent) && extent.IsSignificant)  
        {  
            ITrackingSpan trackingSpan = range.Snapshot.CreateTrackingSpan(extent.Span, SpanTrackingMode.EdgeInclusive);  
            var upperAction = new UpperCaseSuggestedAction(trackingSpan);  
            var lowerAction = new LowerCaseSuggestedAction(trackingSpan);  
            return new SuggestedActionSet[] { new SuggestedActionSet(new ISuggestedAction[] { upperAction, lowerAction }) };  
        }  
        return Enumerable.Empty<SuggestedActionSet>();  
    }   
    
  7. Définir un SuggestedActionsChanged événement.Define a SuggestedActionsChanged event.

    public event EventHandler<EventArgs> SuggestedActionsChanged;  
    
  8. Pour effectuer l’implémentation, ajoutez des implémentations pour les Dispose() et TryGetTelemetryId() méthodes.To complete the implementation, add implementations for the Dispose() and TryGetTelemetryId() methods. Nous ne souhaitons pas faire de télémétrie, donc simplement retourner false et le GUID du jeu vide.We don't want to do telemetry, so just return false and set the GUID to Empty.

    public void Dispose()  
    {  
    }  
    
    public bool TryGetTelemetryId(out Guid telemetryId)  
    {  
        // This is a sample provider and doesn't participate in LightBulb telemetry  
        telemetryId = Guid.Empty;  
        return false;  
    }  
    

Implémentation des Actions d’ampouleImplementing Light Bulb Actions

  1. Dans le projet, ajoutez une référence à Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll et ensemble copie locale à False.In the project, add a reference to Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll and set Copy Local to False.

  2. Créer deux classes, le premier nommé UpperCaseSuggestedAction et la seconde nommée LowerCaseSuggestedAction.Create two classes, the first named UpperCaseSuggestedAction and the second named LowerCaseSuggestedAction. Ces deux classes implémentent ISuggestedAction.Both classes implement ISuggestedAction.

    internal class UpperCaseSuggestedAction : ISuggestedAction   
    internal class LowerCaseSuggestedAction : ISuggestedAction  
    

    Les deux classes sont similaires à ceci près que l’une appelle ToUpper et les autres appels ToLower.Both classes are alike except that one calls ToUpper and the other calls ToLower. Les étapes suivantes traitent uniquement de la classe d’action de mise en majuscules, mais vous devez implémenter les deux classes.The following steps cover only the uppercase action class, but you must implement both classes. Appliquez les étapes d’implémentation de l’action de mise en majuscules comme modèle pour l’implémentation de l’action de mise en minuscules.Use the steps for implementing the uppercase action as a pattern for implementing the lowercase action.

  3. Ajoutez le code suivant à l’aide des instructions pour ces classes :Add the following using statements for these classes:

    using Microsoft.VisualStudio.Imaging.Interop;  
    using System.Windows;  
    using System.Windows.Controls;  
    using System.Windows.Documents;  
    using System.Windows.Media;  
    
  4. Déclarez un ensemble de champs privés.Declare a set of private fields.

    private ITrackingSpan m_span;  
    private string m_upper;  
    private string m_display;  
    private ITextSnapshot m_snapshot;  
    
  5. Ajoutez un constructeur qui définit les champs.Add a constructor that sets the fields.

    public UpperCaseSuggestedAction(ITrackingSpan span)  
    {  
        m_span = span;  
        m_snapshot = span.TextBuffer.CurrentSnapshot;  
        m_upper = span.GetText(m_snapshot).ToUpper();  
        m_display = string.Format("Convert '{0}' to upper case", span.GetText(m_snapshot));  
    }  
    
  6. Implémentez la GetPreviewAsync méthode afin qu’elle affiche l’aperçu de l’action.Implement the GetPreviewAsync method so that it displays the action preview.

    public Task<object> GetPreviewAsync(CancellationToken cancellationToken)  
    {  
        var textBlock = new TextBlock();  
        textBlock.Padding = new Thickness(5);  
        textBlock.Inlines.Add(new Run() { Text = m_upper });  
        return Task.FromResult<object>(textBlock);  
    }  
    
  7. Implémentez le GetActionSetsAsync méthode afin qu’elle retourne un vide SuggestedActionSet énumération.Implement the GetActionSetsAsync method so that it returns an empty SuggestedActionSet enumeration.

    public Task<IEnumerable<SuggestedActionSet>> GetActionSetsAsync(CancellationToken cancellationToken)  
    {  
        return Task.FromResult<IEnumerable<SuggestedActionSet>>(null);  
    }  
    
  8. Implémentez les propriétés comme suit.Implement the properties as follows.

    public bool HasActionSets  
    {  
        get { return false; }  
    }  
    public string DisplayText  
    {  
        get { return m_display; }  
    }  
    public ImageMoniker IconMoniker  
    {  
       get { return default(ImageMoniker); }  
    }  
    public string IconAutomationText  
    {  
        get  
        {  
            return null;  
        }  
    }  
    public string InputGestureText  
    {  
        get  
        {  
            return null;  
        }  
    }  
    public bool HasPreview  
    {  
        get { return true; }  
    }  
    
  9. Implémentez la Invoke méthode en remplaçant le texte dans l’étendue par son équivalent en majuscule.Implement the Invoke method by replacing the text in the span with its uppercase equivalent.

    public void Invoke(CancellationToken cancellationToken)  
    {  
        m_span.TextBuffer.Replace(m_span.GetSpan(m_snapshot), m_upper);  
    }  
    

    Avertissement

    L’action d’ampoule Invoke méthode n’est pas censée afficher l’interface utilisateur.The light bulb action Invoke method is not expected to show UI. Si votre action qu’apporte de la nouvelle interface utilisateur (par exemple une version préliminaire ou la sélection de boîte de dialogue), ne pas afficher l’interface utilisateur directement depuis le Invoke méthode mais au lieu de cela planifier pour afficher votre interface utilisateur après le retour Invoke.If your action does bring up new UI (for example a preview or selection dialog), do not display the UI directly from within the Invoke method but instead schedule to display your UI after returning from Invoke.

  10. Pour terminer l’implémentation, ajoutez le Dispose() et TryGetTelemetryId() méthodes.To complete the implementation, add the Dispose() and TryGetTelemetryId() methods.

    public void Dispose()  
    {  
    }  
    
    public bool TryGetTelemetryId(out Guid telemetryId)  
    {  
        // This is a sample action and doesn't participate in LightBulb telemetry  
        telemetryId = Guid.Empty;  
        return false;  
    }  
    
  11. N’oubliez pas de faire la même chose LowerCaseSuggestedAction modifier le texte d’affichage à « convertir »{0}» en minuscules » et l’appel ToUpper à ToLower.Don't forget to do the same thing for LowerCaseSuggestedAction changing the display text to "Convert '{0}' to lower case" and the call ToUpper to ToLower.

Création et test du codeBuilding and Testing the Code

Pour tester ce code, générez la solution LightBulbTest et exécutez-le dans l’instance expérimentale.To test this code, build the LightBulbTest solution and run it in the Experimental instance.

  1. Générez la solution.Build the solution.

  2. Lorsque vous exécutez ce projet dans le débogueur, une deuxième instance de Visual Studio est instanciée.When you run this project in the debugger, a second instance of Visual Studio is instantiated.

  3. Créez un fichier texte et tapez du texte.Create a text file and type some text. Vous devez voir une ampoule à gauche du texte.You should see a light bulb to the left of the text.

    tester l’ampouletest the light bulb

  4. Pointez sur l’ampoule.Point at the light bulb. Vous devez voir une flèche vers le bas.You should see a down arrow.

  5. Lorsque vous cliquez sur l’ampoule, deux actions suggérées doivent s’afficher, ainsi que la version préliminaire de l’action sélectionnée.When you click the light bulb, two suggested actions should be displayed, along with the preview of the selected action.

    tester l’ampoule, développétest light bulb, expanded

  6. Si vous cliquez sur la première action, tout le texte du mot actuel doit être converti en majuscules.If you click the first action, all the text in the current word should be converted to upper case. Si vous cliquez sur la deuxième action, tout le texte doit être converti en minuscules.If you click the second action, all the text should be converted to lower case.