Dostosowywanie zachowania dotyczącego kopiowania

W języku specyficznym dla domeny (DSL) utworzonym za pomocą zestawu SDK wizualizacji i modelowania programu Visual Studio można zmienić, co się stanie, gdy użytkownik kopiuje i wkleja elementy.

Standardowe zachowanie kopiowania i wklejania

Aby włączyć kopiowanie, ustaw właściwość Włącz kopiowanie wklejenia węzła Edytor w Eksploratorze DSL.

Domyślnie gdy użytkownik kopiuje elementy do schowka, kopiowane są również następujące elementy:

  • Osadzone elementy podrzędne wybranych elementów. (Oznacza to, że elementy, które są elementami docelowymi osadzania relacji, które są źródłowe w skopiowanych elementach).

  • Łącza relacji między skopiowanych elementów.

    Ta reguła jest cyklicznie stosowana do skopiowanych elementów i łączy.

    Copied and pasted elements

    Skopiowane elementy i linki są serializowane i przechowywane w (EGP), który jest umieszczany w ElementGroupPrototype schowku.

    Obraz skopiowanych elementów jest również umieszczany w schowku. Dzięki temu użytkownik może wkleić dane do innych aplikacji, takich jak Word.

    Użytkownik może wkleić skopiowane elementy do obiektu docelowego, który może zaakceptować elementy zgodnie z definicją DSL. Na przykład w języku DSL wygenerowanym na podstawie szablonu rozwiązania składników użytkownik może wkleić porty do składników, ale nie na diagramie; i może wklejać składniki na diagramie, ale nie na inne składniki.

Dostosowywanie zachowania kopiowania i wklejania

Aby uzyskać więcej informacji na temat dostosowywania modelu przy użyciu kodu programu, zobacz Nawigowanie i aktualizowanie modelu w kodzie programu.

Włącz lub wyłącz kopiowanie, wycinanie i wklejanie. W Eksploratorze DSL ustaw właściwość Włącz kopiowanie wklejenia węzła Edytor .

Skopiuj łącza do tego samego obiektu docelowego. Na przykład aby skopiowane pole komentarza było połączone z tym samym elementem tematu. Ustaw właściwość Propagates Copy roli na Propagacja kopiowania, aby połączyć tylko. Aby uzyskać więcej informacji, zobacz Dostosowywanie zachowania kopiowania linków.

Kopiuj połączone elementy. Na przykład podczas kopiowania nowego elementu tworzone są również kopie wszystkich połączonych pól komentarzy. Ustaw właściwość Propagates Copy roli na Propagacja kopiowania, aby połączyć i przeciwny gracz roli. Aby uzyskać więcej informacji, zobacz Dostosowywanie zachowania kopiowania linków.

Szybkie duplikowanie elementów przez kopiowanie i wklejanie. Zwykle skopiowany element jest nadal zaznaczony i nie można wkleić na nim tego samego typu elementu. Dodaj dyrektywę Scalanie elementu do klasy domeny i ustaw ją, aby przekazywać scalania do klasy nadrzędnej. Będzie to miało taki sam wpływ na operacje przeciągania. Aby uzyskać więcej informacji, zobacz Dostosowywanie tworzenia i przenoszenia elementów.

- lub -

Przed wklejeniem elementów wybierz diagram, przesłaniając ClipboardCommandSet.ProcessOnPasteCommand()element . Dodaj ten kod w pliku niestandardowym w projekcie DslPackage:

namespace Company.MyDsl {
using System.Linq;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Shell;
partial class MyDslClipboardCommandSet
{
  protected override void ProcessOnMenuPasteCommand()
  {
 // Deselect the current selection after copying:
 Diagram diagram = (this.CurrentModelingDocView as SingleDiagramDocView).Diagram;
    this.CurrentModelingDocView
     .SelectObjects(1, new object[] { diagram }, 0);
  }
} }

Utwórz dodatkowe linki, gdy użytkownik wkleja go do wybranego obiektu docelowego. Na przykład gdy pole komentarza jest wklejane do elementu, między nimi jest tworzone łącze. Dodaj dyrektywę Scalanie elementu do docelowej klasy domeny i ustaw ją tak, aby przetwarzała scalanie, dodając łącza. Będzie to miało taki sam wpływ na operacje przeciągania. Aby uzyskać więcej informacji, zobacz Dostosowywanie tworzenia i przenoszenia elementów.

- lub -

Zastąpij ClipboardCommandSet.ProcessOnPasteCommand() , aby utworzyć dodatkowe linki po wywołaniu metody podstawowej.

Dostosuj formaty, w których można kopiować elementy do aplikacji zewnętrznych — na przykład w celu dodania obramowania do formularza mapy bitowej. Zastąpij plik MyDslClipboardCommandSet.ProcessOnMenuCopyCommand() w projekcie DslPackage.

Dostosuj sposób kopiowania elementów do schowka za pomocą polecenia kopiowania, ale nie w operacji przeciągania. Zastąpij plik MyDslClipboardCommandSet.CopyModelElementsIntoElementGroupPrototype() w projekcie DslPackage.

Zachowaj układ kształtu za pomocą kopiowania i wklejania. Gdy użytkownik kopiuje wiele kształtów, można zachować ich względne pozycje po wklejeniu. Ta technika jest pokazana w przykładzie w artykule VMSDK: Circuit Diagrams sample (Przykład vmSDK: diagramy obwodu).

Aby osiągnąć ten efekt, dodaj kształty i łączniki do skopiowanego elementu ElementGroupPrototype. Najbardziej wygodną metodą zastąpienia jest ElementOperations.CreateElementGroupPrototype(). W tym celu dodaj następujący kod do projektu Dsl:


public class MyElementOperations : DesignSurfaceElementOperations
{
  // Create an EGP to add to the clipboard.
  // Called when the elements to be copied have been
  // collected into an ElementGroup.
 protected override ElementGroupPrototype CreateElementGroupPrototype(ElementGroup elementGroup, ICollection<ModelElement> elements, ClosureType closureType)
  {
 // Add the shapes and connectors:
 // Get the elements already in the group:
    ModelElement[] mels = elementGroup.ModelElements
        .Concat(elementGroup.ElementLinks) // Omit if the paste target is not the diagram.
        .ToArray();
 // Get their shapes:
    IEnumerable<PresentationElement> shapes =
       mels.SelectMany(mel =>
            PresentationViewsSubject.GetPresentation(mel));
    elementGroup.AddRange(shapes);

 return base.CreateElementGroupPrototype
           (elementGroup, elements, closureType);
  }

 public MyElementOperations(IServiceProvider serviceProvider, ElementOps1Diagram diagram)
      : base(serviceProvider, diagram)
  { }
}

// Replace the standard ElementOperations
// singleton with your own:
partial class MyDslDiagram // EDIT NAME
{
 /// <summary>
 /// Singleton ElementOperations attached to this diagram.
 /// </summary>
 public override DesignSurfaceElementOperations ElementOperations
  {
 get
    {
 if (singleton == null)
      {
        singleton = new MyElementOperations(this.Store as IServiceProvider, this);
      }
 return singleton;
    }
  }
 private MyElementOperations singleton = null;
}

Wklej kształty w wybranej lokalizacji, na przykład bieżące położenie kursora. Gdy użytkownik kopiuje wiele kształtów, można zachować ich względne pozycje po wklejeniu. Ta technika jest pokazana w przykładzie w artykule VMSDK: Circuit Diagrams sample (Przykład vmSDK: diagramy obwodu).

Aby osiągnąć ten efekt, zastąpij ClipboardCommandSet.ProcessOnMenuPasteCommand() użycie wersji specyficznej dla lokalizacji programu ElementOperations.Merge(). W tym celu dodaj następujący kod w projekcie DslPackage:


partial class MyDslClipboardCommandSet // EDIT NAME
{
   /// <summary>
    /// This method assumes we only want to paste things onto the diagram
    /// - not onto anything contained in the diagram.
    /// The base method pastes in a free space on the diagram.
    /// But if the menu was used to invoke paste, we want to paste in the cursor position.
    /// </summary>
    protected override void ProcessOnMenuPasteCommand()
    {

  NestedShapesSampleDocView docView = this.CurrentModelingDocView as NestedShapesSampleDocView;

      // Retrieve data from clipboard:
      System.Windows.Forms.IDataObject data = System.Windows.Forms.Clipboard.GetDataObject();

      Diagram diagram = docView.CurrentDiagram;
      if (diagram == null) return;

      if (!docView.IsContextMenuShowing)
      {
        // User hit CTRL+V - just use base method.

        // Deselect anything that's selected, otherwise
        // pasted item will be incompatible:
        if (!this.IsDiagramSelected())
        {
          docView.SelectObjects(1, new object[] { diagram }, 0);
        }

        // Paste into a convenient spare space on diagram:
    base.ProcessOnMenuPasteCommand();
      }
      else
      {
        // User right-clicked - paste at mouse position.

        // Utility class:
        DesignSurfaceElementOperations op = diagram.ElementOperations;

        ShapeElement pasteTarget = diagram;

        // Check whether what's in the paste buffer is acceptable on the target.
        if (pasteTarget != null && op.CanMerge(pasteTarget, data))
        {

        // Although op.Merge would be a no-op if CanMerge failed, we check CanMerge first
          // so that we don't create an empty transaction (after which Undo would be no-op).
          using (Transaction t = diagram.Store.TransactionManager.BeginTransaction("paste"))
          {
            PointD place = docView.ContextMenuMousePosition;
            op.Merge(pasteTarget, data, PointD.ToPointF(place));
            t.Commit();
          }
        }
      }
    }
  }

Pozwól użytkownikowi przeciągać i upuszczać elementy. Zobacz Instrukcje: dodawanie procedury obsługi przeciągania i upuszczania.

Gdy użytkownik kopiuje element, standardowe zachowanie polega na tym, że wszystkie osadzone elementy są również kopiowane. Możesz zmodyfikować standardowe zachowanie kopiowania. W definicji DSL wybierz rolę po jednej stronie relacji, a w okno Właściwości ustaw wartość Propagacja kopiowania.

Propagates Copy property of domain role

Istnieją trzy wartości:

  • Nie propaguj kopii

  • Propaguj kopię tylko do łącza — gdy grupa zostanie wklejona, nowa kopia tego linku będzie odwoływać się do istniejącego elementu na drugim końcu łącza.

  • Propagacja kopiowania do linku i przeciwnego odtwarzacza ról — skopiowana grupa zawiera kopię elementu na drugim końcu linku.

    Effect of copying with PropagateCopyToLinkOnly

    Wprowadzone zmiany będą mieć wpływ zarówno na elementy, jak i na skopiowany obraz.

Zachowanie kopiowania i wklejania programowania

Wiele aspektów zachowania DSL w odniesieniu do kopiowania, wklejania, tworzenia i usuwania obiektów podlega wystąpieniu ElementOperations , które jest powiązane z diagramem. Zachowanie dsl można zmodyfikować, wyprowadzając własną klasę z ElementOperations klasy i przesłaniając ElementOperations właściwość klasy diagramu.

Napiwek

Aby uzyskać więcej informacji na temat dostosowywania modelu przy użyciu kodu programu, zobacz Nawigowanie i aktualizowanie modelu w kodzie programu.

Sequence diagram for the Copy operation

Sequence diagram of Paste operation

Aby zdefiniować własne elementyOperations

  1. W nowym pliku w projekcie DSL utwórz klasę pochodzącą z DesignSurfaceElementOperationsklasy .

  2. Dodaj definicję klasy częściowej dla klasy diagramu. Nazwę tej klasy można znaleźć w pliku Dsl\GeneratedCode\Diagrams.cs.

    W klasie diagramu zastąpij ElementOperations , aby zwrócić wystąpienie podklasy ElementOperations. Należy zwrócić to samo wystąpienie przy każdym wywołaniu.

    Dodaj ten kod w niestandardowym pliku kodu w projekcie DslPackage:


using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;

  public partial class MyDslDiagram
  {
    public override DesignSurfaceElementOperations ElementOperations
    {
      get
      {
        if (this.elementOperations == null)
        {
          this.elementOperations = new MyElementOperations(this.Store as IServiceProvider, this);
        }
        return this.elementOperations;
      }
    }
    private MyElementOperations elementOperations = null;
  }

  public class MyElementOperations : DesignSurfaceElementOperations
  {
    public MyElementOperations(IServiceProvider serviceProvider, MyDslDiagram diagram)
      : base(serviceProvider, diagram)
    { }
    // Overridden methods follow
  }

Odbieranie elementów przeciągniętych z innych modeli

ElementOperations można również użyć do definiowania zachowania kopiowania, przenoszenia, usuwania i przeciągania i upuszczania. W ramach pokazu użycia elementu ElementOperations w tym przykładzie zdefiniowano niestandardowe zachowanie przeciągania i upuszczania. Jednak w tym celu można rozważyć alternatywne podejście opisane w temacie Instrukcje: Dodawanie procedury obsługi przeciągania i upuszczania, która jest bardziej rozszerzalna.

Zdefiniuj dwie metody w klasie ElementOperations:

  • CanMerge(ModelElement targetElement, System.Windows.Forms.IDataObject data) określa, czy element źródłowy może zostać przeciągnięty do kształtu docelowego, łącznika lub diagramu.

  • MergeElementGroupPrototype(ModelElement targetElement, ElementGroupPrototype sourcePrototype) który łączy element źródłowy w element docelowy.

CanMerge()

CanMerge() element jest wywoływany w celu określenia opinii, które powinny zostać przekazane użytkownikowi w miarę poruszania się myszą na diagramie. Parametry metody to element, nad którym znajduje się wskaźnik myszy, a dane dotyczące źródła, z którego wykonano operację przeciągania. Użytkownik może przeciągać z dowolnego miejsca na ekranie. W związku z tym obiekt źródłowy może mieć wiele różnych typów i może być serializowany w różnych formatach. Jeśli źródłem jest model DSL lub UML, parametr danych jest serializacji klasy ElementGroupPrototype. Operacje przeciągania, kopiowania i przybornika używają elementu ElementGroupPrototypes do reprezentowania fragmentów modeli.

Prototyp grupy elementów może zawierać dowolną liczbę elementów i linków. Typy elementów można zidentyfikować za pomocą ich identyfikatorów GUID. Identyfikator GUID jest kształtem przeciąganym, a nie podstawowym elementem modelu. W poniższym przykładzie zwraca wartość true, CanMerge() jeśli na tym diagramie zostanie przeciągnięty kształt klasy z diagramu UML.

public override bool CanMerge(ModelElement targetShape, System.Windows.Forms.IDataObject data)
 {
  // Extract the element prototype from the data.
  ElementGroupPrototype prototype = ElementOperations.GetElementGroupPrototype(this.ServiceProvider, data);
  if (targetShape is MyTargetShape && prototype != null &&
        prototype.RootProtoElements.Any(rootElement =>
          rootElement.DomainClassId.ToString()
          ==  "3866d10c-cc4e-438b-b46f-bb24380e1678")) // Guid of UML Class shapes
          // or SourceClass.DomainClassId
        return true;
   return base.CanMerge(targetShape, data);
 }

MergeElementGroupPrototype()

Ta metoda jest wywoływana, gdy użytkownik pominie element na diagramie, kształcie lub łączniku. Powinna scalić przeciągniętą zawartość do elementu docelowego. W tym przykładzie kod określa, czy rozpoznaje kombinację typów docelowych i prototypów; jeśli tak, metoda konwertuje przeciągane elementy na prototyp elementów, które powinny zostać dodane do modelu. Metoda podstawowa jest wywoływana w celu wykonania scalania , albo przekonwertowanych lub niekonwertowanych elementów.

public override void MergeElementGroupPrototype(ModelElement targetShape, ElementGroupPrototype sourcePrototype)
{
  ElementGroupPrototype prototypeToMerge = sourcePrototype;
  MyTargetShape pel = targetShape as MyTargetShape;
  if (pel != null)
  {
    prototypeToMerge = ConvertDraggedTypeToLocal(pel, sourcePrototype);
  }
  if (prototypeToMerge != null)
    base.MergeElementGroupPrototype(targetShape, prototypeToMerge);
}

Ten przykład dotyczy elementów klasy UML przeciągniętych z diagramu klas UML. Język DSL nie jest przeznaczony do przechowywania klas UML bezpośrednio, ale zamiast tego tworzymy element DSL dla każdej przeciągniętej klasy UML. Byłoby to przydatne, na przykład, jeśli DSL jest diagramem wystąpienia. Użytkownik może przeciągnąć klasy na diagram, aby utworzyć wystąpienia tych klas.


private ElementGroupPrototype ConvertDraggedTypeToLocal (MyTargetShape snapshot, ElementGroupPrototype prototype)
{
  // Find the UML project:
  EnvDTE.DTE dte = snapshot.Store.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
  foreach (EnvDTE.Project project in dte.Solution.Projects)
  {
    IModelingProject modelingProject = project as IModelingProject;
    if (modelingProject == null) continue; // not a modeling project
    IModelStore store = modelingProject.Store;
    if (store == null) continue;
    // Look for the shape that was dragged:
    foreach (IDiagram umlDiagram in store.Diagrams())
    {
      // Get modeling diagram that implements UML diagram:
      Diagram diagram = umlDiagram.GetObject<Diagram>();
      Guid elementId = prototype.SourceRootElementIds.FirstOrDefault();
      ShapeElement shape = diagram.Partition.ElementDirectory.FindElement(elementId) as ShapeElement;
      if (shape == null) continue;
      IClass classElement = shape.ModelElement as IClass;
      if (classElement == null) continue;

      // Create a prototype of elements in my DSL, based on the UML element:
      Instance instance = new Instance(snapshot.Store);
      instance.Type = classElement.Name;
      // Pack them into a prototype:
      ElementGroup group = new ElementGroup(instance);
      return group.CreatePrototype();
    }
  }
  return null;
}

Standardowe zachowanie kopiowania

W kodzie w tej sekcji przedstawiono metody, które można zastąpić w celu zmiany zachowania kopiowania. Aby dowiedzieć się, jak osiągnąć własne dostosowania, w tej sekcji przedstawiono kod, który zastępuje metody związane z kopiowaniem, ale nie zmienia standardowego zachowania.

Gdy użytkownik naciska klawisze CTRL+C lub używa polecenia menu Kopiuj, wywoływana jest metoda ProcessOnMenuCopyCommand . Sposób konfigurowania tej konfiguracji można znaleźć w pliku DslPackage\Generated Code\CommandSet.cs. Aby uzyskać więcej informacji na temat sposobu konfigurowania poleceń, zobacz Instrukcje: Dodawanie polecenia do menu skrótów.

Można zastąpić polecenie ProcessOnMenuCopyCommand, dodając częściową definicję klasy MyDslClipboardCommandSet w projekcie DslPackage.

using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;

partial class MyDslClipboardCommandSet
{
  /// <summary>
  /// Override ProcessOnMenuCopyCommand() to copy elements to the
  /// clipboard in different formats, or to perform additional tasks
  /// before or after copying - for example deselect the copied elements.
  /// </summary>
  protected override void ProcessOnMenuCopyCommand()
  {
    IList<ModelElement> selectedModelElements = this.SelectedElements;
    if (selectedModelElements.Count == 0) return;

    // System container for clipboard data.
    // The IDataObject can contain data in several formats.
    IDataObject dataObject = new DataObject();

    Bitmap bitmap = null; // For export to other programs.
    try
    {
      #region Create EGP for copying to a DSL.
      this.CopyModelElementsIntoElementGroupPrototype
                     (dataObject, selectedModelElements);
      #endregion

      #region Create bitmap for copying to another application.
      // Find all the shapes associated with this selection:
      List<ShapeElement> shapes = new List<ShapeElement>(
        this.ResolveExportedShapesForClipboardImages
              (dataObject, selectedModelElements));

      bitmap = this.CreateBitmapForClipboard(shapes);
      if (bitmap != null)
      {
        dataObject.SetData(DataFormats.Bitmap, bitmap);
      }
      #endregion

      // Add the data to the clipboard:
      Clipboard.SetDataObject(dataObject, true, 5, 100);
    }
    finally
    {
      // Dispose bitmap after SetDataObject:
      if (bitmap != null) bitmap.Dispose();
    }
  }
/// <summary>
/// Override this to customize the element group that is copied to the clipboard.
/// </summary>
protected override void CopyModelElementsIntoElementGroupPrototype(IDataObject dataObject, IList<ModelElement> selectedModelElements)
{
  return this.ElementOperations.Copy(dataObject, selectedModelElements);
}
}

Każdy diagram ma pojedyncze wystąpienie elementu ElementOperations. Możesz dostarczyć własne pochodne. Ten plik, który można umieścić w projekcie DSL, zachowuje się tak samo jak kod, który zastępuje:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;

namespace Company.MyDsl
{
  partial class MyDslDiagram
  {
    /// <summary>
    /// Singleton ElementOperations attached to this diagram.
    /// </summary>
    public override DesignSurfaceElementOperations ElementOperations
    {
      get
      {
        if (this.elementOperations == null)
        {
          this.elementOperations = new MyElementOperations(this.Store as IServiceProvider, this);
        }
        return this.elementOperations;
      }
    }
    private MyElementOperations elementOperations = null;
  }

  // Our own version of ElementOperations so that we can override:
  public class MyElementOperations : DesignSurfaceElementOperations
  {
    public MyElementOperations(IServiceProvider serviceProvider, ElementOps1Diagram diagram)
      : base(serviceProvider, diagram)
    { }

    /// <summary>
    /// Copy elements to the clipboard data.
    /// Provides a hook for adding custom data.
    /// </summary>
    public override void Copy(System.Windows.Forms.IDataObject data,
      ICollection<ModelElement> elements,
      ClosureType closureType,
      System.Drawing.PointF sourcePosition)
    {
      if (CanAddElementGroupFormat(elements, closureType))
      {
        AddElementGroupFormat(data, elements, closureType);
      }

      // Override these to store additional data:
      if (CanAddCustomFormat(elements, closureType))
      {
        AddCustomFormat(data, elements, closureType, sourcePosition);
      }
    }

    protected override void AddElementGroupFormat(System.Windows.Forms.IDataObject data, ICollection<ModelElement> elements, ClosureType closureType)
    {
      // Add the selected elements and those implied by the propagate copy rules:
      ElementGroup elementGroup = this.CreateElementGroup(elements, closureType);

      // Mark all the elements that are not embedded under other elements:
      this.MarkRootElements(elementGroup, elements, closureType);

      // Store in the clipboard data:
      ElementGroupPrototype elementGroupPrototype = this.CreateElementGroupPrototype(elementGroup, elements, closureType);
      data.SetData(ElementGroupPrototype.DefaultDataFormatName, elementGroupPrototype);
    }

    /// <summary>
    /// Override this to store additional elements in the element group:
    /// </summary>
    protected override ElementGroupPrototype CreateElementGroupPrototype(ElementGroup elementGroup, ICollection<ModelElement> elements, ClosureType closureType)
    {
      ElementGroupPrototype prototype = new ElementGroupPrototype(this.Partition, elementGroup.RootElements, elementGroup);
      return prototype;
    }

    /// <summary>
    /// Create an element group from the given starting elements, using the
    /// copy propagation rules specified in the DSL Definition.
    /// By default, this includes all the embedded descendants of the starting elements,
    /// and also includes reference links where both ends are already included.
    /// </summary>
    /// <param name="startElements">model elements to copy</param>
    /// <param name="closureType"></param>
    /// <returns></returns>
    protected override ElementGroup CreateElementGroup(ICollection<ModelElement> startElements, ClosureType closureType)
    {
      // ElementClosureWalker finds all the connected elements,
      // according to the propagate copy rules specified in the DSL Definition:
      ElementClosureWalker walker = new ElementClosureWalker(this.Partition,
        closureType, // Normally ClosureType.CopyClosure
        startElements,
        true, // Do not load other models.
        null, // Optional list of domain roles not to traverse.
        true); // Include relationship links where both ends are already included.

      walker.Traverse(startElements);
      IList<ModelElement> closureList = walker.ClosureList;
      Dictionary<object, object> closureContext = walker.Context;

      // create a group for this closure
      ElementGroup group = new ElementGroup(this.Partition);
      group.AddRange(closureList, false);

      // create the element group prototype for the group
      foreach (object key in closureContext.Keys)
      {
        group.SourceContext.ContextInfo[key] = closureContext[key];
      }

      return group;
    }
  }
}

Uwaga

Składnik Przekształcanie szablonu tekstu jest automatycznie instalowany w ramach obciążenia programistycznego rozszerzenia programu Visual Studio. Można go również zainstalować na karcie Poszczególne składniki Instalator programu Visual Studio w kategorii Zestawy SDK, biblioteki i struktury. Zainstaluj składnik Zestawu SDK modelowania na karcie Poszczególne składniki.