向我解释以下VS 2010扩展示例代码

时间:2011-02-17 07:23:06

标签: c# visual-studio-2010

Coders,我正在构建VS 2010扩展,我正在试验VS 2010 SDK附带的一些示例。

其中一个示例项目称为TextAdornment。在该项目中,有一个类似于以下内容的怪人类:

[Export(typeof(IWpfTextViewCreationListener))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal sealed class TextAdornment1Factory : IWpfTextViewCreationListener

当我正在尝试这个项目时,我尝试调试项目以查看程序的流程,并且我注意到当我第一次开始调试时,这个类会受到攻击。

现在我的问题如下:是什么让这个类成为VS启动时调用的第一个类?换句话说,为什么这个类被激活并且它在某些代码中运行时实例化了这个类类型的对象?

以下是示例项目中仅有的两个文件:

TextAdornment1Factory.cs

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

namespace TextAdornment1
{
    #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 TextAdornment1Factory : IWpfTextViewCreationListener
    {
        /// <summary>
        /// Defines the adornment layer for the adornment. This layer is ordered 
        /// after the selection layer in the Z-order
        /// </summary>
        [Export(typeof(AdornmentLayerDefinition))]
        [Name("TextAdornment1")]
        [Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Text)]
        [TextViewRole(PredefinedTextViewRoles.Document)]
        public AdornmentLayerDefinition editorAdornmentLayer = null;

        /// <summary>
        /// Instantiates a TextAdornment1 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 TextAdornment1(textView);
        }
    }
    #endregion //Adornment Factory
}

TextAdornment1.cs

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

namespace TextAdornment1
{
    ///<summary>
    ///TextAdornment1 places red boxes behind all the "A"s in the editor window
    ///</summary>
    public class TextAdornment1
    {
        IAdornmentLayer _layer;
        IWpfTextView _view;
        Brush _brush;
        Pen _pen;

        ITextView textView;

        public TextAdornment1(IWpfTextView view)
        {
            _view = view;
            _layer = view.GetAdornmentLayer("TextAdornment1");
            textView = view;

            //Listen to any event that changes the layout (text changes, scrolling, etc)
            _view.LayoutChanged += OnLayoutChanged;
            _view.Closed += new System.EventHandler(_view_Closed);
            //selectedText();

            //Create the pen and brush to color the box behind the a's
            Brush brush = new SolidColorBrush(Color.FromArgb(0x20, 0x00, 0x00, 0xff));
            brush.Freeze();
            Brush penBrush = new SolidColorBrush(Colors.Red);
            penBrush.Freeze();
            Pen pen = new Pen(penBrush, 0.5);
            pen.Freeze();

            _brush = brush;
            _pen = pen;
        }

        void _view_Closed(object sender, System.EventArgs e)
        {
            MessageBox.Show(textView.Selection.IsEmpty.ToString());
        }

        /// <summary>
        /// On layout change add the adornment to any reformatted lines
        /// </summary>
        private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
        {
            foreach (ITextViewLine line in e.NewOrReformattedLines)
            {
                this.CreateVisuals(line);
            }
        }

        private void selectedText()
        {

        }
        /// <summary>
        /// Within the given line add the scarlet box behind the a
        /// </summary>
        private void CreateVisuals(ITextViewLine line)
        {
            //grab a reference to the lines in the current TextView 
            IWpfTextViewLineCollection textViewLines = _view.TextViewLines;
            int start = line.Start;
            int end = line.End;

            //Loop through each character, and place a box around any a 
            for (int i = start; (i < end); ++i)
            {
                if (_view.TextSnapshot[i] == 'a')
                {
                    SnapshotSpan span = new SnapshotSpan(_view.TextSnapshot, Span.FromBounds(i, i + 1));
                    Geometry g = textViewLines.GetMarkerGeometry(span);
                    if (g != null)
                    {
                        GeometryDrawing drawing = new GeometryDrawing(_brush, _pen, g);
                        drawing.Freeze();

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

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

                        //Align the image with the top of the bounds of the text geometry
                        Canvas.SetLeft(image, g.Bounds.Left);
                        Canvas.SetTop(image, g.Bounds.Top);

                        _layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, image, null);
                    }
                }
            }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

如果我理解正确,您想知道TextViewCreated(IWpfTextView textView)中textview的值来自何处。由于这是一个示例项目VS插件,它在编辑器窗口中的所有A下绘制红色框,我怀疑textview是一个指向VS的编辑器窗口的变量(或VS本身的某种对象,它将自己应用于所有在VS中使用合适的窗户,以便所有这些窗户在其A下都有红色框。

现在,如果您调试示例项目,VS会加载插件并调用TextViewCreated(IWpfTextView textView)来应用插件。因为调试器只会停留在示例项目中的代码上,而不会停留在VS本身的代码中,这是第一个被命中的类。它不是第一个被执行的类。这是VS的主要类。

现在,你称之为怪人类:

[Export(typeof(IWpfTextViewCreationListener))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal sealed class TextAdornment1Factory : IWpfTextViewCreationListener

所以我怀疑你不熟悉VS中的插件系统通常如何工作。插件通常是一类(或多个类),其中包含[Export(typeof(IWpfTextViewCreationListener))] [ContentType("text")][TextViewRole(PredefinedTextViewRoles.Document)]Export(typeof(IWpfTextViewCreationListener)。它们定义元数据(即关于类本身的数据)。他们告诉VS这个类是什么(即插件)。例如,TextAdornment1Factoryattributes并告诉VS,类IWpfTextViewCreationListener应该被实例化为TextAdornment1Factory类,而不是[TextLength(min=5, max=10]类。

如果您查看示例export attribute,则属性几乎遍布各处。我曾经用它们自己编写验证框架。这使得添加/删除验证规则变得非常容易和快速,并且使得类非常易读,因为所有执行繁重工作的代码都隐藏在另一个类的某个地方。您只看到{{1}}等属性。

现在,如果你想知道VS如何读取属性,那就是WPF。通过反射,代码可以将其他代码作为对象加载并查看它。例如,您可以使用代码确定一个类有多少方法,参数是什么,......并且,一旦分析,您可以调用这些方法。它构成了一个非常强大的概念,因为它允许代码分析和重写自己。或编写编写代码的代码。

答案 1 :(得分:1)

这不完全正确。 Visual Studio内置了对MEF的支持,导出属性只告诉VS该类实现IWpfTextViewCreationListener并且可以由VS导入。在后台,VS加载安装在其中的所有软件包,并将所有启用MEF的软件包添加到其MEF容器中。

当打开编辑器时,VS会在所有导入的具有相应ContentType集的IWpfTextViewCreationListener上调用TextViewCreated。