饭饭TXT > 学习管理 > 《Visual Studio 2010 高级编程(英文出书版)》作者:Nick Randolph/等【完结】 > [Visual.Studio.2010.高级编程].Professional.Visual.Studio.2010.txt

第 150 页

作者:Nick Randolph/等 当前章节:15374 字 更新时间:2026-6-18 14:51

1038 .

chaPter 53 mAnAged exTenSibiliTy FrAmeWork (meF)

this contract by supplying either a string or a type to the constructor of either the ImportAttribute

or the ExportAttribute. The following code snippet shows three exports that all have the same

contract:

c#

class Settings

{

[Export]

public string Username;

[Export(typeof(string))]

public string Password;

[Export("System.String")]

public string Server;

}

Code snippet GettingStarted\Settings.cs

Vb

Public Class Settings

< Export() >

Dim Username As String

< Export(GetType(String)) >

Dim Password As String

< Export("System.String") >

Dim Server As String

End Class

Code snippet GettingStarted\Settings.vb

It is recommended to use a type for the contract, because a fully qualified type

name is more likely to be unique. If you need to use string contracts, you should

come up with a way of ensuring they are all unique.

You can specify a contract that is different than the type of the export, if required. The best reason

to do this is if the type implements an interface or inherits from an abstract base class. In the

following sample, the SaveOperation class is not aware of the concrete message sender it will use

and instead imports an abstraction: IMessageService. The CommandLineMessageService exports

itself under the contract of the IMessageService interface. In this way, the SaveOperation class

is able to take advantage of message sending without worrying about the details of how these

messages are being sent. If you wanted to change the way the application worked later, you could

implement a new IMessageService and then change which concrete type exported the contract.

Getting started with Mef .

1039

c#

public interface IMessageService

{

void SendMessage(string message);

}

[Export(typeof(IMessageService))]

public class CommandLineMessageService : IMessageService

{

public void SendMessage(string message)

{

Console.WriteLine(message);

}

}

public class SaveOperation

{

[Import]

public IMessageService MessageService { get; set; }

public void DoSave()

{

MessageService.SendMessage("Saving...");

// Perform the save operation

MessageService.SendMessage("Saved");

}

}

Code snippet GettingStarted\SaveOperation.cs

Vb

Public Interface IMessageService

Sub SendMessage(ByVal message As String)

End Interface

<Export(GetType(IMessageService))>

Public Class CommandLineMessageService

Implements IMessageService

Public Sub SendMessage(ByVal message As String) _

Implements IMessageService.SendMessage

Console.WriteLine(message)

End Sub

End Class

Public Class SaveOperation

<Import()>

Public Property MessageService As IMessageService

Public Sub DoSave()

1040 .

chaPter 53 mAnAged exTenSibiliTy FrAmeWork (meF)

MessageService.SendMessage("Saving...")

' Perform the save operation

MessageService.SendMessage("Saved")

End Sub

End Class

Code snippet GettingStarted\SaveOperation.vb

Exporting abstractions and strings raises a potential issue. If there are many

exports with the same contract, MEF will not know which one to use to satisfy

any given import. If this is the case, you can import an enumerable collection for

a contract instead of a single instance using the ImportMany attribute. It is also

possible to attach more metadata to an export, which you can use to refine the

imports. See http://mef.codeplex.com for more information on this technique.

catalogs

In the sample code so far, the only way that the CompositionContainer is made aware of parts is

by passing instances into the ComposeParts method. This means that your application will need to

know about each part added to the container, which will not work for extensions that need to be

deployed after release. It also gets a little tedious after a while.

Locating parts is the job of a catalog, which can be provided to the CompositionContainer

constructor. If a composition container is constructed with a catalog, it will consult the catalog

whenever it needs to locate an export. MEF ships with four catalogs:

.

A TypeCatalog is created with a list of part types. The parts will be instantiated as

required by the composition container to fulfill the import requirements during part

composition.

.

An AssemblyCatalog is similar to the TypeCatalog except that it scans an entire assembly

looking for part types.

.

A DirectoryCatalog scans a folder structure looking for assemblies, which can be examined

for part types.

.

An AggregateCatalog collects the parts from a number of other catalogs. This is useful

because the composition container constructor is only able to accept a single catalog.

The following code sample demonstrates creating a composition container that will look for parts in

the currently executing assembly and in all of the assemblies in the /Extensions folder:

c#

var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());

var directoryCatalog = new DirectoryCatalog(@".\Extensions\");

The Visual studio 2010 editor .

1041

var aggregateCatalog = new AggregateCatalog(assemblyCatalog, directoryCatalog);

var compositionContainer = new CompositionContainer(aggregateCatalog);

Vb

Dim assemblyCatalog As New AssemblyCatalog(Assembly.GetExecutingAssembly())

Dim directoryCatalog As New DirectoryCatalog(".\Extensions\")

Dim aggregateCatalog As New AggregateCatalog(assemblyCatalog, directoryCatalog)

Dim compositionContainer As New CompositionContainer(AggregateCatalog)

You can create your own catalog by creating a new class that inherits from

ComposablePartCatalog and overriding the Parts property.

advanced Mef

MEF supports a number of advanced scenarios that can be useful to you when you are creating

host applications, or when you are creating add-ons or extensions for another host application.

These include:

.

Exporting properties, fields, and methods

.

Importing fields, methods, and constructor arguments

.

Importing collections

.

Composition batches and recomposition

.

Lazy imports

.Catalog filtering

.

Part lifetimes

.

Importing and exporting custom metadata

See the MEF Programming Guide on http://mef.codeplex.com for more information about

these topics.

the Visual studio 2010 editor

One of the most significant changes in Visual Studio 2010 is the new code and text editor control,

which is written in managed code. This new editor uses MEF to manage its structure, which means

that it imports many predefined contracts. In addition to this, it exports a number of services under

1042 .

chaPter 53 mAnAged exTenSibiliTy FrAmeWork (meF)

predefined contracts that provide access to the presentation layer and the underlying model of the

editor. The new editor is made up of four main subsystems.

the text Model subsystem

The Text Model subsystem is used to represent text and enable its modification. It is a logical model

only, which doesn’t have any responsibility for displaying pixels on the screen.

The chief component of this subsystem is the ITextBuffer, which represents a sequence of characters

that should be displayed by the editor. The ITextBuffer can be persisted to the file system as an

ITextDocument, but it doesn’t need to be. It can be an entirely in-memory representation. To create

new ITextBuffer instances, you can use an ITextBufferFactoryService. Any number of threads

can make changes to an ITextBuffer until one of them calls the TakeThreadOwnership

method.

Whenever an ITextBuffer is changed, a new version is created. Each version is represented as an

immutable ITextSnapshot. Because these snapshots cannot change, any number of threads can

refer to them safely, even if the ITextBuffer that they refer to is still changing.

To make a change to an ITextBuffer, you can use the CreateEdit method to create an instance of

the ITextEdit interface. ITextEdit allows you to replace a span of text in the buffer with a new

set of characters. The ITextEdit instance can be applied to the ITextBuffer by calling its Apply

method. It can be abandoned by calling either the Cancel or Dispose method. Only one ITextEdit

can be instantiated for an ITextBuffer at any given time, and if the buffer is owned by a particular

thread, only that thread can create the edits.

The ITextBuffer interface contains Insert, Replace, and Deleteconvenience

methods, which just wrap up the creation and application of an ITextEditinstance.

All operations within a single ITextEdit occur relative to the initial state of the ITextBuffer at

the time when the edit was created. Because of this you cannot insert some text and then remove it

again within a single edit.

When an ITextEdit is applied, new instances of ITextVersion and ITextSnapshot are created

and a Changed event is raised. The ITextVersion represents the changes between the current state

of the ITextBuffer and the previous state, whereas the ITextSnapshot is a read-only view of the

ITextBuffer after the edit has been applied. The changes in an ITextVersion are represented

as a list of ITextChange instances which, if they are applied to a snapshot, would produce the

subsequent snapshot. This collection is always null

(Nothing) for the most recent version.

the text View subsystem

The Text View subsystem is responsible for managing the display of text on the screen. This

includes which lines should be displayed and how text should be formatted. It is also responsible

for enhancing the text with visual adornments such as the squiggly line, which notifies you of

The Visual studio 2010 editor .

1043

compilation errors. Finally, this subsystem manages the borders around the edges of the editor,

which can be enhanced with additional information.

The main part of this subsystem is the ITextView interface. Instances of this interface are used to

represent text visually on the screen. This is used for the main editor window but also for things like

tooltip text. The ITextView keeps track of three different text buffers through its TextViewModel

property. These are:

.

The data buffer, which is the actual text

.

The edit buffer in which text edits occur

.

The visual buffer, which is actually displayed

Text is formatted based on classifiers (see “The Classification Subsystem”) and decorated with

adornments, which come from adornment providers attached to the text view.

The part of the text that is displayed on the screen is the view port. The view port relies on a

logical coordinate system that has (0,0) as the top left of the text. If the editor is not zoomed or

transformed in any way, each unit of distance in the view is the equivalent of a single pixel. Each

line of text that is displayed on the screen is an instance of the ITextViewLine interface. This

interface can be used to map from pixel points to characters.

Finally, the entire editor and all adornments and margins are contained within an

IWpfTextViewHost.

The Text View subsystem comes in two parts. One part is technology agnostic

and is found in the Microsoft.VisualStudio.Text.UI assembly. The other

part is the WPF implementation and is found in the Microsoft.VisualStudio.Text.UI.WPF assembly. In most cases, the WPF-specific items contain the text

“Wpf” in the name.

the classification subsystem

The Classification subsystem manages the recognition and formatting of different types of text. It

is also responsible for tagging text with additional metadata, which will be used by the Text View

subsystem for attaching glyphs and adornments as well as text highlighting and text outlining (such

as collapsed regions of code).

the operations subsystem

The Operations subsystem defines editor behavior and commands. It also provides the Undo

capability.

1044 .

chaPter 53 mAnAged exTenSibiliTy FrAmeWork (meF)

extendinG the editor

Editor extensions are .vsix packages, which export contracts that Visual Studio components will

import. When Visual Studio loads these packages, it adds their contents to a MEF catalog, which

is then used to compose parts of the editor control. The Visual Studio Integration SDK comes

with a number of templates to get you started creating editor controls. These appear under the

Extensibility page of the New Project dialog shown in Figure 53-1.

fiGure 53-1

The Visual Studio 2010 SDK is not installed with Visual Studio 2010. You can

download a copy from http://msdn.microsoft.com/en-us/vsx/default.aspx.

If you want to start with a clean slate, you need to use the VSIX Project template. To expose editor

extensions via this package, edit the source.extension.vsixmanifest file, and use the Add

Content button to add the current project as an MEF Component as in Figure 53-2.

extending the editor .

1045

fiGure 53-2

Once your project is set up to contain MEF content, all you need to do is to create classes that

export known extension contracts and Visual Studio will pick them up. In addition to this, you

can import service contracts from Visual Studio that will provide you with access to the full

capabilities of the editor.

During development, editor extensions can be run and debugged in the Experimental Instance of

Visual Studio. The Experimental Instance behaves like a separate installation of Visual Studio with

its own settings and registry. It also manages a separate set of extensions. When you are ready to

deploy your extension to the normal instance of Visual Studio, you can double-click the .vsix

package, which is created as a part of the build process. This package is entirely self-contained, so

you can use it to deploy your extension to other machines as well.

editor extension Points

目录
设置
设置
阅读主题
字体风格
雅黑 宋体 楷书 卡通
字体大小
适中 偏大 超大
保存设置
恢复默认
手机
手机阅读
扫码获取链接,使用浏览器打开
书架同步,随时随地,手机阅读
首 页 < 上一章 章节列表 下一章 > 尾 页