为 Visual Studio 2010 开发扩展插件
之前看到有国外的大神开发了一些非常好玩的 Visual Studio 扩展插件,觉得非常有意思,自己也参考了别人的代码做了一个插件。
首先需要安装 Visual Studio SDK ,安装不需要其它的工具就可以,直接使用 Visual Studio 安装包。
安装完成后打开 Visual Studio 2010,创建一个名为 VSEditorBackgroud 的 VSIX Project:文件(File)-> 新建(New)-> 项目(Project)->Visual C#->Extensibility-> VSIX Project,名称为 VSEditorBackgroud。
添加 Config 类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; using System.IO; namespace VSEditorBackgroud { [Serializable] public class Config { public ImageConfig BackgroundImage; private static Config _Config = null; [XmlAttribute] public double LayerOpacity; private static object staticSyncRoot = new object(); public Config() { this.LayerOpacity = 0.5; this.BackgroundImage = new ImageConfig(); } public static Config CreatePure() { Config config = new Config(); return config; } public static Config CurrentConfig { get { lock (staticSyncRoot) { XmlSerializer serializer = new XmlSerializer(typeof(Config), new XmlRootAttribute("ImageConfig")); bool IsCreate = false; if (_Config == null) { if (File.Exists(ConfigConsts.ConfigPath)) { try { using (StreamReader reader = new StreamReader(ConfigConsts.ConfigPath)) { _Config = (Config)serializer.Deserialize(reader); } IsCreate = true; } catch { } } if (!IsCreate) { _Config = CreatePure(); try { using (StreamWriter writer = new StreamWriter(ConfigConsts.ConfigPath, false, ConfigConsts.NoBomUTF8)) { serializer.Serialize(writer, _Config, ConfigConsts.VoidNamespaceMapping); } } catch { } } } } return _Config; } } [Serializable] public class ImageConfig { [XmlAttribute] public double Opacity = 1.0; public string Uri = "\t"; } } }
添加 ConfigConsts 类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Threading; using System.Xml.Serialization; namespace VSEditorBackgroud { internal static class ConfigConsts { public static readonly string ConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "\\Visual Studio 2010\\Settings", "VSEditorBackgroud.config"); private static Encoding nobomutf8; public static Encoding NoBomUTF8 { get { if (nobomutf8 == null) { Interlocked.CompareExchange<Encoding>(ref nobomutf8, new UTF8Encoding(false), null); } return nobomutf8; } } public static XmlSerializerNamespaces VoidNamespaceMapping { get { XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces(); namespaces.Add("", ""); return namespaces; } } } }
编辑器背景类 EditorBackgroud:
using System.Windows.Controls; using System.Windows.Media; using Microsoft.VisualStudio.Text.Editor; using System.Windows.Media.Imaging; using System; namespace VSEditorBackgroud { /// <summary> /// Adornment class that draws a square box in the top right hand corner of the viewport /// </summary> public class EditorBackgroud { private Image _image; private IWpfTextView _view; private IAdornmentLayer _adornmentLayer; /// <summary> /// 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 /// </summary> /// <param name="view">The <see cref="IWpfTextView"/> upon which the adornment will be drawn</param> public EditorBackgroud(IWpfTextView view) { _view = view; Config _Config = Config.CurrentConfig; //Grab a reference to the adornment layer that this adornment should be added to _adornmentLayer = view.GetAdornmentLayer("VSEditorBackgroud"); _adornmentLayer.Opacity = _Config.LayerOpacity; ApplyImageConfig(_Config.BackgroundImage); _view.ViewportHeightChanged += delegate { this.onSizeChange(); }; _view.ViewportWidthChanged += delegate { this.onSizeChange(); }; } private void ApplyImageConfig(Config.ImageConfig config) { if (config != null) { try { Image image = new Image(); string uri = config.Uri; BitmapImage bgImage = new BitmapImage(); bgImage.BeginInit(); bgImage.CreateOptions = BitmapCreateOptions.IgnoreImageCache; bgImage.CacheOption = BitmapCacheOption.OnLoad; bgImage.UriSource = new Uri(uri); bgImage.EndInit(); image.Stretch = Stretch.Fill; image.Opacity = config.Opacity; image.Source = bgImage; this._image = image; } catch { } } } public void onSizeChange() { //clear the adornment layer of previous adornments _adornmentLayer.RemoveAllAdornments(); if (this._image != null && !this._image.Width.Equals(this._view.ViewportWidth)) this._image.Width = this._view.ViewportWidth; if (this._image != null && !this._image.Height.Equals(this._view.ViewportHeight)) this._image.Height = this._view.ViewportHeight; //Place the image in the top right hand corner of the Viewport Canvas.SetLeft(_image, _view.ViewportLeft); Canvas.SetTop(_image, _view.ViewportTop); //add the image to the adornment layer and make it relative to the viewport _adornmentLayer.AddAdornment(AdornmentPositioningBehavior.ViewportRelative, null, null, _image, null); } } }
EditorFactory 类:
using System.ComponentModel.Composition; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities; namespace VSEditorBackgroud { #region Adornment Factory /// <summary> /// Establishes an <see cref="IAdornmentLayer"/> to place the adornment on and exports the <see cref="IWpfTextViewCreationListener"/> /// that instantiates the adornment on the event of a <see cref="IWpfTextView"/>'s creation /// </summary> [Export(typeof(IWpfTextViewCreationListener))] [ContentType("text")] [TextViewRole(PredefinedTextViewRoles.Document)] internal sealed class PurpleBoxAdornmentFactory : IWpfTextViewCreationListener { /// <summary> /// Defines the adornment layer for the scarlet adornment. This layer is ordered /// after the selection layer in the Z-order /// </summary> [Export(typeof(AdornmentLayerDefinition))] [Name("VSEditorBackgroud")] [Order(After = PredefinedAdornmentLayers.Outlining)] [TextViewRole(PredefinedTextViewRoles.Document)] public AdornmentLayerDefinition editorAdornmentLayer = null; /// <summary> /// Instantiates a Wen manager when a textView is created. /// </summary> /// <param name="textView">The <see cref="IWpfTextView"/> upon which the adornment should be placed</param> public void TextViewCreated(IWpfTextView textView) { new EditorBackgroud(textView); } } #endregion //Adornment Factory }
修改 source.extension.vsixmanifest 文件的信息:
<?xml version="1.0" encoding="utf-8"?> <Vsix xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010"> <Identifier Id="3f2ce087-8d13-492c-a207-e1fdbfd1cf58"> <Name>VSEditorBackgroud</Name> <Author>Charles Zhang</Author> <Version>1.0.0.5</Version> <Description xml:space="preserve">The Visual Studio Editor Backgroud plugin. </Description> <Locale>4</Locale> <License>license.rtf</License> <Icon>icon.ico</Icon> <PreviewImage>PreviewImage.jpg</PreviewImage> <SupportedProducts> <VisualStudio Version="10.0"> <Edition>Ultimate</Edition> <Edition>Premium</Edition> <Edition>Pro</Edition> <Edition>Express_All</Edition> </VisualStudio> <VisualStudio Version="11.0"> <Edition>Ultimate</Edition> <Edition>Premium</Edition> <Edition>Pro</Edition> <Edition>Express_All</Edition> </VisualStudio> </SupportedProducts> <SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="4.5" /> </Identifier> <References /> <Content> <MefComponent>|%CurrentProject%|</MefComponent> </Content> </Vsix>
在项目中添加一个 PreviewImage.jpg 用做插件的预览图,添加 icon.ico 用做扩展的图标。
编译项目,安装生成的 Vsix 文件。
安装好以后在扩展管理器中的效果如下:
编辑器的效果如下:
以上就是 Visual Studio 2010 开发扩展插件的过程了。