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);
}
}
}
}
}
}发布于 2011-02-17 14:05:49
如果我正确地理解了您,您希望知道TextViewCreated(IWpfTextView textView)中文本视图的值来自何处。因为这是一个示例项目VS插件,它在编辑器窗口的所有A下绘制红色框,因此我怀疑textview是指向VS编辑器窗口的变量(或者VS自身的某种对象,它将自己应用于VS中所有合适的窗口,以便所有这些窗口的A下都有红色的框)。
现在,如果调试示例项目,VS将加载插件并调用TextViewCreated(IWpfTextView textView)应用插件。因为调试器只在示例项目中的代码上停止,而不是在VS本身的代码中停止,而VS本身是第一个命中的类。它不是正在执行的第一个类。这是VS的主要课程。
现在,你说这是个古怪的课程:
[Export(typeof(IWpfTextViewCreationListener))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal sealed class TextAdornment1Factory : IWpfTextViewCreationListener因此,我怀疑您并不熟悉VS中的插件系统是如何工作的。插件通常是一个包含大量属性的类(或多个类)( [Export(typeof(IWpfTextViewCreationListener))]、[ContentType("text")]和[TextViewRole(PredefinedTextViewRoles.Document)]就是这样)。它们定义元数据(即关于类本身的数据)。他们告诉VS这个类是用来做什么的(即插件)。例如,Export(typeof(IWpfTextViewCreationListener)是一个导出属性,并告诉VS类TextAdornment1Factory应该实例化为IWpfTextViewCreationListener类,而不是TextAdornment1Factory类。
例如,如果您看一看WPF,属性实际上无处不在。我曾经亲自使用它们来编写验证框架。这使得添加/删除验证规则变得非常简单和快速,并且使类非常可读性强,因为所有执行繁重任务的代码都隐藏在另一个类的某个地方。您只看到了像[TextLength(min=5, max=10]这样的属性。
现在,如果您想知道VS是如何读取属性的,这是通过反射实现的。通过反射,代码可以将其他代码作为对象加载并查看它。例如,您可以用代码计算出一个类有多少个方法,参数是什么,.一旦分析完毕,你就可以调用这些方法了。它提供了一个非常强大的概念,因为它允许代码分析和重写自己。或者编写写代码的代码。
发布于 2011-02-23 15:25:28
这不是完全正确的。Visual构建了对MEF的支持,导出属性只告诉VS这个类实现了IWpfTextViewCreationListener,并且它可以由VS导入。在背景中,VS加载安装在其中的所有包,并将所有启用MEF的包添加到其MEF容器中。
打开编辑器时,VS调用具有相应ContentType集的所有导入的IWpfTextViewCreationListener上的ContentType。
;)
https://stackoverflow.com/questions/5026161
复制相似问题