Click here to Skip to main content
Click here to Skip to main content

Getting started with Visual Studio Editor Viewport Adornment Extensions

, 17 Jul 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
This article will help you to start with Visual Studio Editor Viewport Adornment Extensions, Sample extension 'File Properties Info'.

Introduction

In this article I'm going to give a quick start on Editor View Adornment Extension, For demonstrating this project template I'm using a sample extension named as "File Info". If you haven't gone through my previous article on Editor Margin Extension, then I encourage you to read that before you start on this.

File Properites Window, File Storage Info Visual Studio Editor Viewport Adornment Extension

If you are talking about this project template then I can say the Viewport is the area of the text view that is currently displayed in the editor and by default the Editor Viewport Adornment project template creates a viewport-relative adornment that adds a violet box that has a red outline to the top-right corner of the viewport. We can easily customize this to anything programatically that we want.

You might be interested in below plugins which are created by me,

Editor Viewport Adornment

This template provides a bare bones editor visual that is positioned relative to the editore's visual surface. This basic basic viewport- relative adornament puts a purple box in the top right hand corner of the editor's viewport. If you would like to get a detailed introduction about exntesibily project templates then please read my article  "Getting started with Visual Studio Editor Margin Extensions"

Let us create a simple Editor Viewport Adornment extension. To start with, Open up Visual Studio and create a new Editor Viewport Adornament project called ViewportAdornment1.

(New Project->Templates->C#->Extensibility)

Viewport Adornment Extension File Properties Inside Visual Studio

Click OK, now we have the basic project ready,

Viewport Adornment Extension File Properties Inside Visual Studio

Visual Studio has created a sample Viewport Adornment for us, the generated codes are given below,

ViewportAdornment1Factory.cs

using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Utilities;

namespace ViewportAdornment1
{
    #region Adornment Factory
    [Export(typeof(IWpfTextViewCreationListener))]
    [ContentType("text")]
    [TextViewRole(PredefinedTextViewRoles.Document)]
    internal sealed class PurpleBoxAdornmentFactory : IWpfTextViewCreationListener
    {
        [Export(typeof(AdornmentLayerDefinition))]
        [Name("ViewportAdornment1")]
        [Order(After = PredefinedAdornmentLayers.Caret)]
        public AdornmentLayerDefinition editorAdornmentLayer = null;

        public void TextViewCreated(IWpfTextView textView)
        {
            new ViewportAdornment1(textView);
        }
    }
    #endregion //Adornment Factory
}

The above class Establishes an IAdornmentLayer to place the adornment on and exports the IWpfTextViewCreationListener that instantiates the adornment on the event of a IWpfTextView's creation. Then defines the adornment layer for the scarlet adornment. This layer is ordered after the selection layer in the Z-order and finally the TextViewCreated method Instantiates a ViewportAdornment1 manager when a textView is created.

ViewportAdornment1.cs

The TextViewCreated method from PurpleBoxAdornmentFactory calls the below class constructor which accepts IWpfTextView as a parameter.

using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;

namespace ViewportAdornment1
{

    class ViewportAdornment1
    {
        private Image _image;
        private IWpfTextView _view;
        private IAdornmentLayer _adornmentLayer;

        public ViewportAdornment1(IWpfTextView view)
        {
            _view = view;

            Brush brush = new SolidColorBrush(Colors.BlueViolet);
            brush.Freeze();
            Brush penBrush = new SolidColorBrush(Colors.Red);
            penBrush.Freeze();
            Pen pen = new Pen(penBrush, 0.5);
            pen.Freeze();

            //draw a square with the created brush and pen
            System.Windows.Rect r = new System.Windows.Rect(0, 0, 30, 30);
            Geometry g = new RectangleGeometry(r);
            GeometryDrawing drawing = new GeometryDrawing(brush, pen, g);
            drawing.Freeze();

            DrawingImage drawingImage = new DrawingImage(drawing);
            drawingImage.Freeze();

            _image = new Image();
            _image.Source = drawingImage;

            //Grab a reference to the adornment layer that this adornment should be added to
            _adornmentLayer = view.GetAdornmentLayer("ViewportAdornment1");

            _view.ViewportHeightChanged += delegate { this.onSizeChange(); };
            _view.ViewportWidthChanged += delegate { this.onSizeChange(); };
        }

        public void onSizeChange()
        {
            //clear the adornment layer of previous adornments
            _adornmentLayer.RemoveAllAdornments();

            //Place the image in the top right hand corner of the Viewport
            Canvas.SetLeft(_image, _view.ViewportRight - 60);
            Canvas.SetTop(_image, _view.ViewportTop + 30);

            //add the image to the adornment layer and make it relative to the viewport
            _adornmentLayer.AddAdornment(AdornmentPositioningBehavior.ViewportRelative, null, null, _image, null);
        }
    }
}

ViewportAdornment1 class that draws a square box in the top right hand corner of the viewport.  ViewportAdornment1(IWpfTextView view) creates a square image and attaches an event handler to the layout changed event that adds the the square in the upper right-hand corner of the TextView via the adornment layer.

Now Lets run the application to see the output, before running our application we need make sure that the Author(or Publisher) value is populated in source.extension.vsixmanifest.

Viewport Adornment Extension File Properties Inside Visual Studio

For the File Info sample plugin, I have done small changes to the generated file, so that the square box appear on bottom right corner with a small size.

<s>System.Windows.Rect r = new System.Windows.Rect(0, 0, 30, 30);</s>
System.Windows.Rect r = new System.Windows.Rect(0, 0, 8, 8)
....
....
....
_image.ToolTip = "File Info";
_image.Cursor = System.Windows.Input.Cursors.Hand;
_image.MouseDown += new System.Windows.Input.MouseButtonEventHandler(_image_MouseDown);

the above code is to change the rectangle size and to add an event handler to the rectangle image. below code change is to change the rectangle image location to bottom right corner of the editor.

<s>Canvas.SetLeft(_image, _view.ViewportRight - 60);
Canvas.SetTop(_image, _view.ViewportTop + 30);</s>
Canvas.SetLeft(_image, _view.ViewportRight - 9);
Canvas.SetTop(_image, _view.ViewportBottom - 9);

Now I have added a simple code in ViewportAdornment1 constructor to retrieve the current document path 

_view = view;

ITextBuffer TextBuffer = _view.TextBuffer;

ITextDocument TextDocument = GetTextDocument(TextBuffer);

if (TextDocument == null || TextDocument.FilePath == null || TextDocument.FilePath.Equals("Temp.txt"))
{
    return;
}

_filePath = TextDocument.FilePath;

also I have included a using "Microsoft.VisualStudio.Text;" and "private string _filePath = string.Empty;"

public ITextDocument GetTextDocument(ITextBuffer TextBuffer)
{
    if (TextBuffer == null)
        return null;

    ITextDocument textDoc;
    var rc = TextBuffer.Properties.TryGetProperty<ITextDocument>(
      typeof(ITextDocument), out textDoc);
    if (rc == true)
        return textDoc;
    else
        return null;
}

I have used ShellExecuteEx to display the Properties dialog box for a file. Now add a class file named "clsSHELLEXECUTEINFO.cs" and replace the content with below codes,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows;

namespace ViewportAdornment1
{
    public static class clsSHELLEXECUTEINFO
    {
        const int SEE_MASK_INVOKEIDLIST = 0x00000C;
        const int SEE_MASK_NOCLOSEPROCESS = 0x000040;
        const int SEE_MASK_FLAG_NO_UI = 0x000400;

        [StructLayout(LayoutKind.Sequential)]
        internal struct SHELLEXECUTEINFO
        {
            internal int cbSize;
            internal uint fMask;
            internal IntPtr hwnd;
            [MarshalAs(UnmanagedType.LPWStr)]
            internal string lpVerb;
            [MarshalAs(UnmanagedType.LPWStr)]
            internal string lpFile;
            [MarshalAs(UnmanagedType.LPWStr)]
            internal string lpParameters;
            [MarshalAs(UnmanagedType.LPWStr)]
            internal string lpDirectory;
            internal int nShow;
            internal IntPtr hInstApp;
            internal IntPtr lpIDList;
            [MarshalAs(UnmanagedType.LPWStr)]
            internal string lpClass;
            internal IntPtr hkeyClass;
            internal uint dwHotKey;
            internal IntPtr hIcon;
            internal IntPtr hProcess;
        }

        public static void ShowFilePropertyDlg(string path)
        {
            SHELLEXECUTEINFO info =
                new SHELLEXECUTEINFO();

            info.cbSize = Marshal.SizeOf(info);
            info.hwnd = IntPtr.Zero;

            info.fMask = (SEE_MASK_INVOKEIDLIST |
                SEE_MASK_NOCLOSEPROCESS |
                SEE_MASK_FLAG_NO_UI);

            //Properties dialog
            //for file or folder
            //to be displayed
            info.lpVerb = "properties";

            //using file path which is passed as a parameter         
            info.lpFile = path;

            if (!ShellExecuteEx(ref info))
            {
                int lastError = Marshal.GetLastWin32Error();

                MessageBox.Show(
                    string.Format("Could not open properties window.\nShellExecuteEx failed with error code: {0}",
                    lastError));
            }
        }

        [DllImport("shell32.dll", SetLastError = true,
            EntryPoint = "ShellExecuteExW",
            CharSet = CharSet.Unicode)]
        static extern bool ShellExecuteEx(
            ref SHELLEXECUTEINFO lpExecInfo);
    }
}

In the above class, the method ShowFilePropertyDlg(string path) can be used to show properties window of a file. Now update the _image_MouseDown with the method call.

void _image_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    clsSHELLEXECUTEINFO.ShowFilePropertyDlg(_filePath);
}

References

Summary

In this article I have tried to explain How to create a Visual Studio Viewport Adornment Extension with a simple sample, I hope you have enjoyed this article and got some value addition to your knowledge.

I have put my time and efforts on all of my articles, please don't forget to mark your votes, suggestions and feedback to improve the quality of this and upcoming articles.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Shemeer NS
Software Developer (Senior)
India India
Technology Specialist | CodeProject MVP | Visual Studio Gallery Contributor | Author | Geek | Netizen | Husband | ChessPlayer
 
Most of my articles are listed on top 5 of the respective 'Best articles of the month' and some of my articles are published on ASP.NET WebSite's Article of the Day section.
 
Check my contributions in Visual Studio Gallery and Code Project
 
Technical Blog: http://www.shemeerns.com
Facebook: http://facebook.com/shemeernsblog
Twitter : http://twitter.com/shemeerns
Google+ : http://google.com/+Shemeernsblog
Follow on   Twitter   Google+

Comments and Discussions

 
QuestionCannot see the first picture Pinmemberleiyangge16-Jul-14 16:21 
AnswerRe: Cannot see the first picture PinmvpShemeer NS17-Jul-14 0:26 
GeneralRe: Cannot see the first picture Pinmemberleiyangge17-Jul-14 6:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141220.1 | Last Updated 17 Jul 2014
Article Copyright 2014 by Shemeer NS
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid