Walkthrough: Adding Features to a Custom Editor

After you create a custom editor, you can add more features to it.

To create an editor for a VSPackage

  1. Create a custom editor by using the Visual Studio Package project template.

    For more information, see Walkthrough: Creating a Menu Command By Using the Visual Studio Package Template.

  2. Decide whether you want your editor to support a single view or multiple views.

    An editor that supports the New Window command, or has form view and code view, requires separate document data objects and document view objects. In an editor that supports only a single view, the document data object and the document view object can be implemented on the same object.

    For an example of multiple views, see Supporting Multiple Document Views.

  3. Implement an editor factory by implementing the IVsEditorFactory interface.

    For more information, see Editor Factories.

  4. Decide whether you want your editor to use in-place activation or simplified embedding to manage the document view object window.

    A simplified embedding editor window hosts a standard document view, while an in-place activation editor window hosts an ActiveX control or other active object as its document view. For more information, see Simplified Embedding and In-Place Activation.

  5. Implement the IOleCommandTarget interface to handle commands.

  6. Provide document persistence and response to external file changes by doing the following:

    1. To persist the file, implement IVsPersistDocData2 and IPersistFileFormat on your editor's document data object.

    2. To respond to external file changes, implement IVsFileChangeEx and IVsDocDataFileChangeControl on your editor's document data object.

      Note

      Call QueryService on SVsFileChangeEx to obtain a pointer to IVsFileChangeEx.

  7. Coordinate document edit events with source code control. To do this:

    1. Obtain a pointer to IVsQueryEditQuerySave2 by calling QueryService on SVsQueryEditQuerySave.

    2. When the first edit event occurs, call the QueryEditFiles method.

      This prompts the user to check out the file if it is not already checked out. Be sure to handle a "file not checked out" condition to avert errors

    3. Similarly, before saving the file, call the QuerySaveFile method.

      This method prompts the user to save the file if it has not been saved or if it has changed since the last save.

  8. Enable the Properties window to display properties for text selected in the editor. To do this:

    1. Call OnSelectChange each time text selection changes, passing in your implementation of ISelectionContainer.

    2. Call QueryService on STrackSelection service to obtain a pointer to ITrackSelection.

  9. Enable users to drag and drop items between the editor and the Toolbox, or between external editors (like Microsoft Word) and the Toolbox. To do this:

    1. Implement IDropTarget on your editor to alert the IDE that your editor is a drop target.

    2. Implement the IVsToolboxUser interface on the view so your editor can enable and disable items in the Toolbox.

    3. Implement ResetDefaults and call QueryService on SVsToolbox service to obtain a pointer to the IVsToolbox2 and IVsToolbox3 interfaces.

      This enables your VSPackage to add new items to the Toolbox.

  10. Decide whether you want any other optional features for your editor.

    • If you want your editor to support find and replace commands, implement IVsFindTarget.

    • If you want your editor to support macro recording, call QueryService for SVsMacroRecorder to obtain a pointer to IVsMacroRecorder.

      Note

      The IDE supports macro recording when the editor supports it.

    • If you want to use a document outline tool window in your editor, implement IVsDocOutlineProvider.

    • If you want to use a status bar in your editor, implement IVsStatusbarUser and call QueryService for SVsStatusbar to obtain a pointer to IVsStatusBar.

      For example, an editor can display line / column information, selection mode (stream / box), and insertion mode (insert / overstrike).

    • If you want your editor to support the Undo command, the recommended method is to use the OLE undo manager model. As an alternative, you can have the editor handle the Undo command directly.

  11. Create registry Information, including the GUIDs for the VSPackage, the menus, the editor, and other features.

    The following is a generic example of code that you would put in your .rgs file script to demonstrate how to properly register an editor.

    NoRemove Editors
    {
          ForceRemove {...guidEditor...} = s 'RTF Editor'
          {
             val Package = s '{...guidVsPackage...}'
             ForceRemove Extensions
             {
                val rtf = d 50
             }
          }
    }
    NoRemove Menus
    {
          val {...guidVsPackage...} = s ',203,11'
    }
    
  12. Implement context-sensitive Help support.

    This allows you to provide F1 Help and Dynamic Help window support for items in your editor. For more information on this, see How to: Provide Context for Editors.

  13. Expose an Automation Object Model from your editor by implementing the IDispatch interface.

    For more information, see Contributing to the Automation Model.

Robust Programming

  • The editor instance is created when the IDE calls the CreateEditorInstance method. If the editor supports multiple views, CreateEditorInstance creates both the document data and the document view objects. If the document data object is already open, a non-null punkDocDataExisting value is passed to IVsEditorFactory::CreateEditorInstance. Your editor factory implementation must determine whether an existing document data object is compatible by querying for appropriate interfaces on it. For more information, see Supporting Multiple Document Views.

  • If you use the simplified embedding approach, implement the IVsWindowPane interface.

  • If you decide to use in-place activation, implement the following interfaces:

    IOleObject

    IOleInPlaceActiveObject

    IOleInPlaceComponent

    Note

    The IOleInPlaceComponent interface is used to avoid OLE 2 menu merging.

    Your IOleCommandTarget implementation handles commands such as Cut, Copy, and Paste. When implementing IOleCommandTarget, decide whether your editor requires its own .vsct file to define its own command menu structure or if it can implement standard commands defined by Visual Studio. Typically, editors use and extend the IDE's menus and define their own toolbars. However, it often is necessary for an editor to define its own specific commands in addition to using the IDE's standard command set. To do this, your editor must declare the standard commands it uses and then define any new commands, context menus, top-level menus and toolbars in a .vsct file. If you create an in-place activation editor, then implement IOleInPlaceComponent and define the menus and toolbars for the editor in a .vsct file instead of using OLE 2 menu merging.

  • To prevent menu command crowding in the UI, you should use the existing commands in the IDE before inventing new commands. Shared commands are defined in SharedCmdDef.vsct and ShellCmdDef.vsct. These files are installed by default in the VisualStudioIntegration\Common\Inc subdirectory of your Visual Studio SDK installation.

  • ISelectionContainer can express both single and multiple selections. Each selected object is implemented as an IDispatch object.

  • The IDE implements IOleUndoManager as a service accessible from a CreateInstance or as an object that can be instantiated through CreateInstance. Your editor implements the IOleUndoUnit interface for each Undo action.

  • There are two places a custom editor can expose automation objects:

    • Document.Object

    • Window.Object

See Also

Tasks

How to: Provide Context for Editors

Other Resources

Contributing to the Automation Model